分工、同步、互斥。
- 分工:如何高效地拆解任务并分配给线程 (
ForkJoinPool
) - 同步:线程之间如何协作 (
CountDownLatch
) - 互斥:保证同一时刻只允许一个线程访问共享资源 (
ReentrantLock
)
基本概念
- 可见性:多核 CPU 缓存所导致的问题
- 原子性:CPU 分片调度机制,导致指令执行顺序不保证【 i++ 分散在多个指令中】
- 有序性:编译器优化导致语句顺序调整
为平衡 CPU、内存、IO 设备之间地性能差异:
- CPU 增加了三级缓存
- 操作系统增加了进程、线程,以分时复用 CPU
- 编译程序优化指令执行次序,使得缓存能够得到更加合理的利用
缓存导致的可见性问题
线程切换带来的原子性问题
完成 count+=1
至少需要三条 CPU 指令:
- 首先,需要把变量 count 从内存加载到 CPU 寄存器
- 之后,在寄存器中执行
+1
操作 - 最后,将结果写入内存 (缓存机制导致可能写入的是 CPU 缓存,而不是内存)
操作系统做任务切换,可以发生在任何一条CPU 指令执行完,而不是高级语言里的一条语句。
编译优化带来的有序性问题
|
|
new 操作可能被优化成:
- 分配一块内存 M
- 将 M 的地址赋值给 instance 变量
- 最后在内存 M 上初始化 Singleton 对象
JMM
解决可见性、有序性最直接的办法就是禁用缓存和编译优化。
Happens-Before
前面一个操作的结果对后续操作是可见的。
|
|
- 程序的顺序性规则:程序对某个变量的修改一定是对后续操作可见的
- volatile 变量规则:对一个 volatile 变量的写操作,先于后续对这个 volatile 变量的读操作
- 传递性规则:如果 A 操作先于 B 操作,且 B 先于 C,那么 A 先于 C
- 管程中锁的规则:对一个锁的解锁先于后续对这个锁的加锁【管程是一种通用的同步原语,Java 中的 synchronized】
- 线程 start() 规则:主线程 A 启动子线程 B 后,子线程 B 能够看到主线程在启动子线程 B 前的操作
- 线程 join() 规则:主线程 A 等待子线程 B 完成,当子线程 B 退出后,主线程能够看到子线程的操作
死锁
- 互斥 - 共享资源 X 和 Y 只能被一个线程占用
- 占有且等待 - 线程 A 已经取得共享资源 X,在等待共享资源 Y 时不释放共享资源 X
- 不可抢占 - 其他线程不能强行抢占线程 A 的资源
- 循环等待 - 线程 A 等待线程 B 占有的资源,线程 B 等待线程 A 占有的资源
线程
Runnable <-> Blocked
线程等待 synchronized 隐式锁;
synchronized 修饰的方法、代码块同一时刻只允许一个线程执行,其他线程只能等待,此时,等待的线程从 RUNNABLE 切换到 BLOCKED
Runnable <-> Waiting
Object.wait
Thread.join
LockSupport.park
Runnable <-> Timed_Waiting
Thread.sleep(long milis)
Object.wai(long timeout)
Thread.join(long milis)
LockSupport.parkNanos(Object bloker, long deadline)
LockSupport.parkUntil(long deadline)
Runnable -> Terminated
Thread.stop
Thread.interrupt
stop() 方法真的会杀死线程,不给线程喘息机会,如果线程持有 ReentrantLock
,被 stop 的线程并不会自动调用 unlock 方法,可能会导致其他线程无法获取到该锁,进而产生系统问题。【最好不使用】
interrupt() 方法仅仅是通知线程,线程有机会执行一些后续操作,同时也可以无视这个通知。
|
|
在触发 InterruptedException 异常的同时,JVM 会同时把线程的中断标志位清除,所以这个时候 th.isInterrupted()返回的是 false。
|
|
并发策略
- 避免共享【ThreadLocal 思想】
- 不变模式【合理使用 final】
- 管程及其他同步工具【sychronized】
- 优先使用成熟的工具类
- 迫不得已才使用低级的同步原语
- 避免过早优化
锁
锁,应是私有的,不可变的,不可重用的
用锁的最佳实践
- 永远只在更新对象的成员变量时加锁
- 永远只在访问可变的成员变量时加锁
- 永远不在调用其他对象的方法时加锁
JUC
- Semaphore
- ReadWriteLock
- StampedLock
- CountDownLatch
- CyclicBarrier
Blocking*
Atomic*