《深入理解高并发编程》学习笔记
最近在学习的《深入理解高并发编程》 因此写点笔记来帮助日后回顾学习
幕后黑手
可见性
根因:缓存 表现:多线程处理同一变量,最终处理结果与预期不一致。
原子性
根因:线程切换 表现:多线程处理同一变量,最终处理结果与预期不一致。
有序性
根因:指令重排 表现:双重检查单例模式 new Instance() 指令重排导致线程B获取到线程A还未创建的对象
解决办法
按照需要禁用缓存和编译优化
java内存模型
Java内 存模型规范了Java虚拟机(JVM)如何提供按需禁用缓存和编译优化的方法
volatile
禁用CPU缓存
volatile int count = 0
Happens-Before原则
程序次序规则
同一线程里,修改变量对后续操作一定是可见的
volatile变量规则
volatile修饰的变量的写操作,先于 读操作
传递规则
A>B, B>C ==> A>B>C
锁定规则
synchronized
线程启动规则
A 启动 B,那么B能看到A在启动B前的各操作
线程终结规则
A中调用B.join() B执行完后 A继续执行,此时B的操作对A是可见的
线程中断规则
A中中断B ,B可以访问A的修改
对象终结原则
synchronized的原理
通过对象或者类上的monitor监视器锁来解决同步问题
修饰代码块 -> 锁定传入对象 修饰方法 -> 锁定当前实例对象this 修饰静态方法 -> 锁定是当前类对象
互斥锁解决原子性问题
ThreadLocal
线程A和线程B存储在ThreadLocal中的变量互不干扰,线程A存储的变量只能由线程A访问,线程B存 储的变量只能由线程B访问
根本原因在于,变量map其实是存在各自thread对象里,ThreadLocal仅仅是个白手套 InheritableThreadLocal 解决ThreadLocal 无法让子线程获取父线程ThreadLocal 变量的问题
并发问题的核心
分工
大任务分解成小任务交给合适的线程处理 Executor、Fork/Join和Future都是实现分工的一种方式。
同步
一个线程执行完任务后,如何通知其他的线程继续执行 CountDownLatch、 CyclicBarrier
互斥
同一时刻,只允许一个线程访问共享变量,强调的是线程执行任务的正确性。 synchronized、Lock、ThreadLocal、final