Java多线程
线程基础
-
进程与线程
进程:操作系统分配资源的最小单位
线程:CPU执行的最小单位
-
线程分类
1. 用户线程 用户自己创建的业务线程; 2. 守护线程 为用户线程提供服务的线程,如GC; 通过thread.setDaemon(true);设为守护线程,且必须放在start方法前;
-
4种线程创建方式
1. 继承Thread类; 2. 实现Runnable接口; 3. 实现Callable接口(可结合FutureTask返回结果,并支持抛出异常); 4. 通过线程池创建;
-
2种线程数量选择
1. IO密集型 n = 2 * CPU核数 2. CPU密集型 n = CPU核数 + 1
-
5类线程状态
-
- sleep与wait的区别
1. sleep 让出cpu,不释放锁 2. wait 让出cpu,释放锁。依赖synchronized
-
- 线程中断方式
thread.interrupt
通过抛出异常中断线程。
stop方法不推荐,会导致死锁
-
Happens-Before原则
定义 代码经过编译器优化后才会执行,有种优化方式为:指令重排,而指令重排必须遵守Happens-Before原则
规则名称 | 描述 |
---|---|
程序顺序规则 | 一个线程的每个操作,happens-before于该线程中的任意后续操作。 注:此处操作指前一个操作的结果对后一个操作可见,若不满足不允许重排。 |
监视器锁规则 | 对一个锁的解锁,happens-before于后续对这个锁的加锁。 |
volatile规则 | 对volatile变量的写,happens-before于后续对这个变量的读。 |
传递性 | 若 A happens-before B,B happens-before C,则 A happens-before C。 |
线程启动规则 | Thread对象的start方法,happens-before这个线程后续任意操作。 |
线程终止规则 | 线程中任意操作,happens-before该线程的终止。 |
线程中断规则 | 对线程的interrupt操作,happens-before对该线程中断事件的检测。 |
对象终结规则 | 对象初始化完成,happens-before该对象的finalize方法。 |
锁
-
锁分类
锁 | 定义 |
---|---|
公平锁与非公平锁 | 公平锁:多线程按照申请锁的顺序获取锁。 eg:ReentrantLock可通过构造函数指定是否公平(默认非公平锁) 非公平锁:不按申请顺序获取锁,有可能造成饥饿锁。 eg:synchronized |
独享锁与共享锁 | 独享锁:一个锁只能被一个线程持有。 eg:synchronized与ReentrantLock都是独享锁。 共享锁:一个锁可被多个线程持有。 ReadWriteLock中,读锁是共享锁,写锁是独享锁。 |
乐观锁与悲观锁 | 乐观锁:对同一数据并发操作,认为不一定会更新数据,因此采取不断尝试更新的操作(如CAS自旋) 悲观锁:对同一数据并发操作,认为一定会更新数据,因此会加锁实现同步。 注:这两者不是具体的锁,是指看待并发同步的角度。 |
分段锁 | 细化锁的操作。eg:给数组中某一个元素加锁。 ConcurrentHashMap有个Entry数组,数组中每个元素是一个链表,也是一个Segment(分段锁)。当put元素时,不是对整个hashMap加锁(hashTable是),而是通过hashCode知道它在哪一分段,然后对这个分段加锁。 注:这不是具体的锁,是一种锁设计。 |
偏向锁、轻量级锁、重量级锁 | 这3种锁是synchronized锁的状态,通过对象监视器在对象头中的字段区分。 eg:synchronized锁升级过程 1.偏向锁:一段同步代码一直被一个线程访问,那么该线程自动获取这个锁(降低获取锁的代价) 2.轻量级锁:当前锁为偏向锁,且被另一个线程访问时,偏向锁升级为轻量级锁,其他线程通过自旋尝试获取锁,不会阻塞其他线程 3.重量级锁:当前锁为轻量级锁,其他线程自旋到一定次数还没获取到锁,轻量级锁升级为重量级锁,阻塞其他线程。 |
可重入锁 | 同一线程,在外层方法获取到锁之后,进入内层方法自动获取锁。 |