Java多线程体系
1.并发编程的优势
提升CPU资源利用率
提升吞吐量
提升程序响应速度
更好的编程模型
2.并发带来的问题
1.安全性问题
-
0.定义:什么是安全性问题
-
多线程读写共享变量时出现不正确的结果
- 共享变量
- 多线程读&写
- 不正确结果
-
-
1.出现安全性问题的原因
-
0.原子性问题
- CPU时钟中断带来的线程切换
-
1.可见性问题
- 多核CPU高速缓存之间不可见
-
2.重排序问题
-
CPU和编译器会进行重排序指令
- 典型问题:单例模式DCL
-
-
-
2.解决方案
-
解决原子性问题
-
0.前置知识
-
CPU硬件如何实现原子性
-
#LOCK信号总线锁
- 原子指令:CMPXCHG/XADD/BTS
-
缓存锁定(缓存一致性协议)
-
-
-
1.CAS无锁算法
-
底层使用CMPXCHG原子指令
-
CAS三大注意事项
- ABA问题
- 循坏开销大
- 多变量问题
-
实现方法
- unsafe工具类
-
-
2.通用互斥锁管程模型
-
管程
-
定义
- 管理并发过程中的共享变量及其操作过程
-
MESA模型
-
线程阻塞队列
-
条件变量
-
条件变量等待队列
-
编程范式
-
while循坏检测
- 虚假唤醒
- 条件变更
-
-
-
-
sychronized
-
对象头锁结构
-
锁优化
-
偏向锁
-
轻量级锁
-
重量级锁
-
底层ObjectMonitor
- _waitSet
- _EntryList
- _cxq
-
-
-
-
-
-
解决可见性问题和重排序
-
Java内存模型(JMM)
-
按需禁用缓存和编译优化(重排序)
- volatile
- final
-
Happens-Before规则
- 要求前一个操作的结果对后一个操作可见
-
-
-
并发包实现基石
- volatile变量读写+CAS无锁算法
-
并发同步工具和机制
-
基于AQS的同步组件
-
原子变量
- AtomicLong
- LongAdder
-
等待通知机制
- wait
- notify/notifyAll
-
线程封闭
- ThreadLocal
-
非阻塞同步机制
-
-
活跃性问题
-
死锁
-
定义
- 一组相互竞争资源的线程因互相等待,导致”永久“阻塞的现象
-
死锁的四大条件
-
互斥
- 共享资源只能被一个线程占用
-
占有且等待
- 已占有资源的线程,在等待其他资源时不释放原有资源
-
不可抢占
- 线程不能抢占其他线程已占有的资源
-
循环等待
- 出现线程之间相互等待对方资源的情况
-
-
打破死锁
-
打破“占有且等待”
- 一次性申请所有资源
-
打破“不可抢占”
-
已占有资源的线程,如果申请不到其他资源,主动释放原有资源
- 并发包的LOCK
-
-
打破“循环等待”
- 按统一顺序申请资源
-
-
-
活锁
-
没有阻塞但不满足条件无法继续执行
- 等待随机时间
-
-
饥饿
-
长期获取不到资源无法继续执行
- 公平分配
-
性能问题
-
Amdahl定律
- 使用无锁算法和数据结构 - ThreadLocal - 写时复制 - 乐观锁 - 减小锁持有范围 - 细粒度锁 - 分段锁 - 读写锁
-
上下文切换
- 合理配置并发线程数
-
伪共享
-
原因
- 最小单位缓存行
-
解决方案
- 变量填充
- jdk8 @Contended
-
-
衡量指标
- 吞吐量
- 延迟时间
- 并发量
3.线程生命周期
通用状态
-
初始状态
- 编程语言特有,操作系统层还没有真正创建
-
运行状态
- 运行中
-
可运行状态
- 可分配CPU执行
-
休眠状态
-
终止状态
Java线程状态
-
NEW(初始化)
-
RUNNABLE(可运行状态/运行状态)
-
BLOCKED(阻塞状态)
- synchronized
-
WAITING(无限时等待)
-
TIMED_WAITING(有限时等待)
- sleep
- wait()带超时参数
- join()带超时参数
- LockSupport.park()带超时参数
-
TERMINATED
4.并发工具类
Condition
AQS
-
同步状态
- state
-
同步队列
- CLH
-
模板方法
-
独占式获取和释放同步状态
-
获取
-
void acquire(int args)
- 独占式获取
-
void acquireInterruptibly(int args)
- 可响应中断
-
boolean tryAcquireNanos(int args,long nanos)
- 在响应中断的基础上加入了超时机制
-
-
释放
-
release(int args)
- 独占式释放
-
-
-
共享式获取和释放同步状态
-
获取
-
acquireShared(int args)
- 共享式获取
-
acquireSharedInterruptibly(int args)
- 可响应中断
-
tryAcquireSharedNanos(int args,long nanos)
- 在响应中断的基础上加入了超时机制
-
-
释放
-
releaseShared(int args)
- 独占式释放
-
-
-
查询同步队列线程集合
- getQueuedThreads()
-
-
重写方法
- tryAcquire(int args)
- tryRelease(int args)
- tryAcquireShared(int args)
- tryReleaseShared(int args)
- isHeldExclusively
Lock
-
和synchronized的区别
- 响应中断
- 支持超时
- 非阻塞式获取锁
ReadWriteLock和StampedLock
-
ReadWriteLock
-
读锁
- 高16位表示读锁状态
-
写锁
- 低16位表示写锁状态
-
锁不能升级,只能降级。升级会使写锁永久阻塞等待
-
写锁支持条件变量,读锁是不支持条件变量的
-
-
StampedLock
- 写锁
- 悲观读锁
- 乐观读
- 加锁成功会返回stamp,解锁需要传入stamp
- 性能更好
- 不可重入
- 不支持条件变量
- 使用readLock() 或writeLock() 时,不能使用阻塞线程的interrupt(),需要使用可中断的悲观读锁 readLockInterruptibly() 和写锁 writeLockInterruptibly()
Semaphore
CountDownLatch
- 解决一个线程等待多个线程的场景
- 计数器是不能循环利用
CyclicBarrier
- 一组线程之间互相等待
- 计数器是可以循环利用,自动重置
- 可以设置回调函数
并发容器类
-
List
- CopyOnWriteArrayList
-
Map
- ConcurrentHashMap
- ConcurrentSkipListMap
-
Set
- CopyOnWriteArraySet
- ConcurrentSkipListSet
-
Queue
-
.单端阻塞队列
- ArrayBlockingQueue
- LinkedBlockingQueue
- SynchronousQueue
- LinkedTransferQueue
- PriorityBlockingQueue
- DelayQueue
-
双端阻塞队列
- LinkedBlockingDeque
-
单端非阻塞队列
- ConcurrentLinkedQueue
-
双端非阻塞队列
- ConcurrentLinkedDeque
-
原子类
-
基本数据类型
- AtomicBoolean
- AtomicInteger
- AtomicLong
-
对象引用类型
- AtomicReference
- AtomicStampedReference
- AtomicMarkableReference
-
数组类型
- AtomicIntegerArray
- AtomicLongArray
- AtomicReferenceArray
-
对象属性更新器
- AtomicIntegerFieldUpdater
- AtomicLongFieldUpdater
- AtomicReferenceFieldUpdater
-
累加器
- DoubleAccumulator
- DoubleAdder
- LongAccumulator
- LongAdder
线程池
- ThreadPoolExecutor
- Executors
- Future
- FutureTask
- CompletableFuture
- CompletionService
- Fork/Join
5.并发设计模式
Immutability模式
- 基础类型包装类
Copy-on-Write模式
- 基础类型包装类
线程本地存储模式
- ThreadLocal
Guarded Suspension模式
- 等待唤醒机制
Balking模式
Thread-Per-Message模式
- 协程
- Fiber
Worker Thread模式
- Java线程池
两阶段终止模式
生产者-消费者模式
- Java线程池
- MQ
6.Java异步编程技术
显时使用线程
- 实现Runnable接口
- 继承Thread类
显时使用线程池
- 实现方式
基于Future实现
- FutureTask
- CompletableFuture
基于反应式编程
- 基于RxJava
- 基于Reactor