学习时有关多线程的一些概念等,作为记录

1、什么是线程?
线程是程序执行的一条路径,一个进程中可以包含多条线程。多线程并发执行可以提高程序的执行效率,同时完成多项工作。
多线程应用场景:
迅雷可以开启多条线程一起下载
服务器可以响应多个客户端的同时请求
qq同时个多个人一起视频

2、并行与并发的区别
并行是两个任务同时运行,需要多核CPU才可实现
并发则是有两个任务同时请求运行,CPU只接受一个任务,安排两个任务轮流进行,只是间隔时间较短,看着像是两个任务同时运行

3、java程序运行原理,JVM是多线程的吗
运行原理
java命令行会启动JVM,相当于启动了一个应用程序,也即启动了一个进程,该进程会启动一个“主线程”,调用某个类的main方法
是否是多线程
JVM的启动至少会启动“主线程”和垃圾回收线程,所以是多线程的

4、多线程实现的方式
(1)通过Thread类
继承Tread类,重写Thread类中的run方法(真正要执行的线程体),将要执行的代码写入run方法中;之后在主方法中创建Thread类的子类对象,调用子类的start方法,开启多线程,该方法会默认调用run方法;run方法执行结束,该线程运行结束
(2)通过实现Runnable接口
实现Runnable接口,重写run方法,将要执行的代码写入run方法中;之后在主方法中创建实现接口的类对象,将该对象作为参数传递构造一个Tread类对象,通过Thread类调用start方法实现多线程
在Thread类中,有一个Thread(Runnable target)的构造方法,将实现Runnable接口的子类传进去之后,会调用方法,将target传入,之后调用Thread的run方法则为调用target的run方法。即为编译看父类,运行看子类。
(3)这两种方式的区别
a:查看源码的区别,
继承Thread类,重写run方法,调用时直接调用子类中重写的方法
实现Runnable接口,将实现Runnable接口的子类作为参数传入Thread类中,调用start方法时会先判断Runnable的引用是否为空,若不为空则调用引用的run方法
b:使用上,
继承Thread类,好处在于直接继承使用,代码简单;弊端在于如果已经有了父类则不可使用
实现Runnable接口,好处在于子类可以继承其他父类,也可以实现其他接口,可扩展性更强,但是代码复杂。
两者应优先考虑继承Thread类,后者更像是前者的补充

5、多线程的一些方法使用
获取名字和设置名字,getName(),setName()得到线程的名字或者设置线程名字,匿名内部类中也可以调用
获取当前线程的对象,Thread.currentThread(),是静态方法,获取当前运行线程的线程对象,通过此可调用该运行线程的各种方法,Thread.currentThread().setName(),设置当前线程的名字等

6、各种线程
(1)休眠线程
当调用线程中的Thread.sleep()方法时,线程进入休眠状态,传入的数据以毫秒为单位,休眠一段时间后继续运行。
(2)守护线程
调用线程中的setDaemon(true)方法,线程设置为守护线程,当非守护线程运行完毕时,守护线程也会结束,即守护线程是为非守护线程服务的。
如qq聊天界面即是qq软件中的守护线程。
(3)加入线程
调用线程中的join()方法,当前线程暂停,等待执行的线程结束后,当前线程再继续执行。类似于中断,另外join(int)可加入整数代表中断执行的时间。
注意:匿名内部类(局部内部类)在使用当前方法中的局部变量时,需将变量改为final类型的。
(4)礼让线程(静态方法)
线程中的yield方法,让出CPU,但是不明显,用的也不多

7,设置线程的优先级
setPriority(value)方法设置线程执行的优先级,最低为1,最高为10,默认为5

8、同步代码块
(1)什么情况下需要同步?
当多线程并发,有多段代码块需要同时执行,在这个执行的过程中并不希望将CPU让出去,而是执行完毕整个代码块之后再让出,这时就需要同步
(2)同步代码块
synchronized关键字加上一个锁对象来定义一段代码,这就叫同步代码块
多个代码块如果使用相同的锁对象,那么他们就是同步的,这个锁对象可以是任意对象,但是必须时相同的才能叫同步的

9、同步方法
在方法声明返回值类型之前加上synchronized关键字为同步方法,非静态的同步方法对象的锁是什么?是this
静态的同步方法对象的锁是类的字节码文件。即用在同步代码块中的锁对象。

10、线程安全问题
当多个线程并发操作同一个数据时容易出现线程安全问题
使用同步代码块或者同步方法可以解决线程安全问题,将同步操作数据的代码块,不多个线程同时操作数据

11、死锁
多线程同步的时候,如果同步代码块嵌套,使用相同锁就容易出现死锁的情况,尽量不要使用嵌套

12、一些线程安全的类
Vector(线程安全),ArrayList(线程不安全);StringBuffer(线程安全),StringBuilder(线程不安全);HashTable(线程安全 ),HashMap(线程不安全);
Collections.synchronized(XXX)可将线程不安全的改为线程安全的,例如:Collections.synchronizedList()

13、单例设计模式
保证类在内存中只有一个对象
如何保证?
1)私有类的构造方法,其他类不可访问该构造方法
private Singleton(){}
2)在类内部创建私有的静态类(静态的)
private static Singleton s = new Singleton();
3)对外提供公共的访问方法
public Singleton getSingleton(){
return s;
}
实现的两种方式:饿汉式(创建对象时就创建类对象)和懒汉式(进入公共访问方法时判断后创建)
两者的区别:饿汉式是空间换时间,懒汉式 是时间换空间;在多线程访问时,饿汉式不会创建多个对象,懒汉式有可能创建多个对象。此外 ,懒汉式会在单例的延迟加载模式中应用。

14、两个常用类
Runtime类,饿汉式单例模式,r.exec(command)允许应用程序与运行应用程序的环境进行接口
Timer类,计时器类,在指定时间安排指定任务

15、线程间的通信
多个线程并发执行时,在默认情况下是随机切换线程的,有时我们希望能够线程有规律的执行,就可以使用线程间通信,如每个线程执行一次(交替执行)
如何通信,如果希望线程等待,调用wait()方法,如果希望唤醒线程,调用notify()方法,设置变量,通过变量的变化来控制线程的等待与唤醒;这两个方法必须在同步代码块中使用,并使用同步锁对象调用(两个线程间的通信)
三个及以上线程间的通信,与上述方法类似,将notify()方法改为notifyAll()方法即可,但是判断变量处应由if改为while
线程间通信需要注意的一些问题:
1)在同步代码块中,用哪个对象锁,就用哪个对象调用wait()方法和notify()方法。
2)为什么wait()和notify()方法封装在Object类中?因为锁对象可以是任意对象,Object是所有类的超类,故而将这两个方法封装在Object类中了
3)sleep方法和wait方法的区别,sleep方法必须有参数传入,传入的参数为线程睡眠的时间;wait方法可传入参数也可不传入参数,传入参数则为过了这个时间就进入等待状态,需要被唤醒才能继续执行该线程,不传入参数则是直接进入等待状态;另外,sleep方法在同步执行代码块中不释放锁,但wait方法在同步代码块中释放锁。

16、互斥锁
使用ReentrantLock类的lock()和unlock()方法实现同步,使用ReentrantLock类中的newCondition()方法得到Condition类,需要等待时用Condition中的await()方法,唤醒时用signal()方法,不同的线程用不同的Condition,就可准确唤醒不同的线程。

17、线程组
ThreadGroup线程组类,默认都在主线程组里,可在创建线程时将创建的线程组名字写入即可。

18、线程的五种状态
1)新建状态:创建一条新的线程
2)就绪状态:线程已经准备好被执行了,但是CPU还未给到该线程执行权,一般在start()方法执行后。
3)运行状态:该线程获得了CPU的执行权,正在执行线程需要运行的内容,run()方法中内容
4)阻塞状态:该线程在运行时被别的线程抢走了执行权,等待CPU再将执行权归还到该线程
5)死亡状态:该线程运行完毕,线程对象变成垃圾被回收。

19、线程池
程序启动一个新线程的成本时较高的,因为要涉及到与操作系统进行交互,而使用线程池可以很好的解决该问题。尤其是需要操作很多生命周期较短的线程时,更应该考虑使用线程池。线程池中的线程在线程结束后不会立即死亡,而是等待下一个对象使用。在JDK5之前,我们需要手动创建自己的线程池,JDK5之后,JAVA内置支持线程池。
使用:Java提供了Executors工厂类来生产线程池,简单使用步骤如下,
通过Executors类中的piblic static ExecutorService newFixThreadPool(int)方法创建有几条线程的线程池,通过ExecutorService类中的submit()方法可将Runnable或者Callable实现的多线程方式提交进线程池。shutdown
()方法可关闭线程池中所有线程。

20、Callable接口实现多线程方法
通过实现Callable接口并重写其中的call方法来实现多线程,其余与Runnable实现多线程步骤类似,但是call方法有返回值,也可抛出异常。返回值可在线程池中提交线程时用Future类接收,随后以get方法得到具体的返回值。
虽然该实现方式可以有返回值并可抛出异常,但是实现的方式有些复杂,故而用的少

21、简单工厂模式
又叫静态工厂方法,通过定义一个具体的工厂类来负责创建不同类对象的实例。比如在线程池的实现过程中,Executors类就是一个工厂类,通过该类创建的ExecutorService线程池。
好处:客户端不需要负责创建对象实例,可以更好的明确各个类的职责
弊端:工厂负责所有类的创建,如果需要增加新的类或者创建类的方式有所不同都需要在工厂中进行修改,后期维护比较麻烦

22、工厂方法模式
抽象工厂类负责定义创建对象的接口,具体对象的创建由继承抽象工厂类负责创建
好处:客户端不需要负责创建对象实例,如果需要增加新的类,只需增加具体的新类和具体的工厂类,不影响已有的代码,增强了系统的可扩展性。
弊端:需要编写额外的代码,增加了工作量

23、适配器设计模式
通常接口中有许多类,但是有时不需要用到所有的方法,但又必须重写,比较繁琐。适配器设计模式可以简化这些操作,只需要继承适配器类就可以想重写那个方法就重写哪个方法。
原理:适配器就是一个类,将所有抽象方法都重写了,但是方法全是空的,然后将适配器设置为抽象类,使之不能被实例化(因为方法是空的,所以实例化没有意义)。目的就是为了简化操作,定义监听器时继承适配器类,只重写需要的方法即可。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值