java并发编程复习
2021-04-17 01:09:25 1 举报
AI智能生成
登录查看完整内容
java并发编程
作者其他创作
大纲/内容
基础
wait/notify,循环检查条件,被通知后也要检查
等待线程终止后才从join返回,线程终止时会调用自身notifyAll(),join底层是synchronized的等待/通知模式
线程本地变量,每个线程一个变量的副本
子线程可以获取到父线程set的值:初始化子线程时会将父线程的InheritableThreadLocal复制一份给子线程的 InheritableThreadLocal
设置一个未来时间点,wait剩余时间后,唤醒后使用未来时间和当前时间的差值更新剩余时间
线程的创建
继承Thread类重新run方法
实现Runnable接口,run()方法
实现Callable接口,call()方法
在run()方法内回去当前线程直接使用this,方便设置参数,缺点是java只支持单继承
有返回值,通过Future.get获取返回值
线程中断
线程不会立即终止,执行线程根据中断标志位来选择如何处理,InterruptedException会清除中断标识
不建议使用,调用后线程不会释放锁资源,容易引发死锁
唤醒suspend()的线程
强制停止,不保证线程资源的正常释放
interrupt()
suspend()
resume()
stop()
等待/通知
join
ThreadLocal
线程持有ThreadLocalMap
子线程无法获取父线程的TheadLocal
内存泄漏问题
key为ThreadLocal引用,value为线程set的值
主要是线程池中的线程会一直存在,导致ThreadLocalMap中的value发生泄漏
InheritableThreadLocal
等待超时
并发容器和工具
ConcurrentHashMap
分段锁,默认16个segment
JDK1.7
get不加锁
put加锁
JDK1.8
CurrentLinkedQueue
阻塞队列
ArrayBlockingQueue
LinkedBlockingQueue
PriorityBlockingQueue
DelayQueue
LinkedBlockingDeque
SynchronousQueue
由数组组成的有界阻塞队列
由链表组成的有界阻塞队列,默认长度Integer.Max_VALUE
支持优先级排序的无界阻塞队列
延迟队列,基于优先队列实现的无界阻塞队列
由链表组成的双向阻塞队列
不存储元素的阻塞队列
Fork/Join
并发原子类
原子方式更新基本类型
AtomicBoolean
AtomicInteger
AtomicLong
原子更新数组
原子更新数组里的元素
更新引用类型数组
AtomicIntegerArray
AtomicLongArray
AtomicReferenceArray
原子更新引用类型
更新引用类型
更新引用类型里的字段
带版本号的更新,解决ABA问题
AtomicReference
AtomicReferenceFieldUpdate
AtomicStampedReference
原子更新字段
AtomicIntegerFieldUpdater
AtomicLongFieldUpdater
并发工具类型
CountDownLatch
1、主线程await时判断计数器state是否为0,不为0则加入AQS队列
2、调用countDown递减state,如果减到0则唤醒AQS队列中的线程
CyclicBarrier
1、使用lock加Condition实现
2、await()时加锁同步递减计数器,未减到0则加入Condition等待队列
3、如果计时器变为0则唤醒Condition等待队列中的所有线程
Semaphore
递增计数器,到达指定数量后加入AQS队列中
Exchanger
直到所有线程到达一个屏障再开始一起执行,先到达的线程会阻塞,可重置reset()
控制同时访问特定资源的线程数量,acquire(),基于AQS实现
两个线程交换数据
调用countDown方法就减1,直至0才不会阻塞主线程,不可重复使用,基于AQS实现
无界线程安全队列,CAS实现
一个任务分成多个子任务执行
CAS
线程池
处理流程
1、核心线程池是否已满,未满则新增线程执行任务
2、核心线程池已满,任务队列未满则加入队列,等待线程消费
3、队列已满,线程数未到最大线程数则创建线程执行
4、已到达最大线程数,执行拒绝策略
线程池参数
corePoolSize
runnableTaskQueue
maximumPoolSize
ThreadFactory
RejectExecutionHandler
AbortPolicy
CallerRunsPolicy
DiscardOldestPolicy
DiscardPolicy
直接抛出异常,默认
调用者线程来执行
丢弃队列最近一个任务并执行当前任务
不处理,丢弃
核心线程池未满即使有空闲线程,新来任务时也创建新线程
任务队列,建议使用有界队列
最大线程数,队列满了会新创建线程
创建线程的工厂
拒绝策略,队列和线程池都满了
提交任务
threadPoolExecutor.execute
threadPoolExecutor.submit
实现Runnable接口
实现Callable接口
关闭线程池
shutdown
shutdownNow
中断空闲线程
中断所有正在执行的线程和空闲的线程
线程池数量
IO密集型
CPU密集型
看IO时间和总处理时间比例
CPU核心数+1
遍历线程池中的工作线程,逐个调用线程的interrupt方法
java并发编程
synchronized原理
monitor指令
monitorenter
monitorexit
方法结束处和异常处
对象头
轻量级锁,指向栈中锁记录指针
重量级锁
GC标记
01
线程头存储线程ID
无锁
偏向锁
00
10
11
锁升级过程
CAS替换MarkWord中的线程ID,失败则升级
复制MarkWord到各自线程栈,然后CAS自旋修改对象的MarkWord指针指向各自线程栈中的MarkWord有线程自旋失败(10次)则升级为重量级锁
轻量级锁
原子操作CAS
ABA问题
循环时间长开销大,消耗CPU
多变量的原子操作
AtomicStampedReference,先检查引用,在检测更新标识,类似版本号
AtomicReference保证引用对象之间的原子性
java内存模型
happens-before
volatile原理
将当前处理器缓存行的数据写回到系统内存
这个写回内存的操作会使其他CPU里缓存了该内存地址的数据无效
防止指令重排序
缓存行填充技术,防止频繁写入导致其他缓存失效
内存屏障,在对volatile变量操作是在前后加入内存屏障防止重排序
final的重拍规则
禁止把final域的写重排序到构造函数之外
读对象的final域之前,一定先读包含这个final域的对象引用
双重检测的单例模式
可见性
前一个操作的执行结果对后一个操作可见
单例对象要使用volatile修饰,或者换成静态内部类延迟初始化
java中的锁
模板方法模式,重写tryAcquire,tryRelease等方法
等待队列,每个AQS多个等待队列
AQS原理
state=1,只有一个线程可以获取
state>1,可以多个线程CAS获取,释放时也要CAS减少,Semaphore
同步队列
获取锁
释放锁
CAS修改state状态失败后会被加入同步队列中自旋获取锁,获取失败则等待
释放成功修改state,并唤醒同步队列中的节点(唤醒头结点的后继结点)
独占式锁
共享式锁
锁类型
同一个线程多次加同一个锁
按加锁顺序依次获取锁,通过AQS实现,如果当前节点有前驱节点则获取失败,由头部节点唤醒后继节点
不检验AQS队列中是否有元素,直接和AQS队列被唤醒的节点一起竞争
读写互斥,读读不互斥
重入锁
ReentrantLock
synchronized
加锁时state变量递增,释放时递减
公平锁
非公平锁
读写锁
读锁
写锁
锁降级
高16位,加读锁是判断低16位是否为0,如果为0则可以加锁
低16位,加锁时判断高16位是否为0,如果不为0则加锁失败
先获取写锁再获取读锁,随后释放写锁,防止其他写锁进行修改
LockSupport
阻塞线程
唤醒线程
park
unpark
Condition
AQS同步队列首节点移动到等待队列中
等待队列首节点移至同步队列再唤醒
将所有等待队列中的节点移至同步队列中,唤醒每个节点
await
signal
signalAll
Executor框架
ThreadPoolExecutor
创建固定线程数的线程池,核心线程数和最大线程数一致
创建单个线程的线程池
根据需要创建新线程池,任务提交速度高于线程处理速度则会一直不停的创建线程线程执行完任务后将空闲下来,如果60秒内没有新任务则终止线程
SingleThreadExecutor
FixedThreadExecutor
CachedThreadExecutor
ScheduleThreadPoolExecutor
单个线程
time
sequenceNumber
period
take()
1、获取time最小任务,大于当前时间则等待time,加到Condition等待队列中
2、如果取出最小任务后PriorityQueue中还有元素则唤醒Condition中线程
offer()
如果添加的任务的time比当前PriorityQueue中的头元素还小则唤醒Condition中的线程
封装了PriorityQueue,time最小排前面,time相同比较序号
将要被执行的具体时间
序号
任务执行间隔
加锁
SingleThreadScheduleExecutor
Future
无返回结果
有返回结果
基于AQS实现
Runnable接口
Callable接口
FutureTask实现
1、FutureTask.get()方法会判断state是否为RAN状态,如果不是则加入AQS队列
2、FutureTask.run()执行完后会更新state为RAN,并设置result为Callable.call()返回值,然后唤醒AQS队列中线程
任何对象都有一个monitor与之关联,持有对象的monitor将处理锁定状态
输入旧值和要更新的值,如果在更新的时候发现当前值和旧值不一样就更新失败
主内存和线程本地内存
0 条评论
回复 删除
下一页