深入浅出 Java Concurrency
2020-05-27 21:39:49 0 举报
AI智能生成
Java并发编程
作者其他创作
大纲/内容
原子操作
原子整数
AtomicBoolean
AtomicInteger
AtomicLong
原子引用
<font color="#0076b3">AtomicReference</font>
AtomicMarkableReference
AtomicStampedReference
原子数组
AtomicIntegerArray
AtomicLongArray
AtomicReferenceArray
字段更新器
AtomicReferenceFieldUpdater
AtomicIntegerFieldUpdater
AtomicLongFieldUpdater
原子累加器
<b><font color="#0076b3">LongAdder</font></b>
Cell
<font color="#0076b3">@sun.misc.Contentd</font><br>防止 <font color="#31a8e0">缓存行</font> <font color="#16884a">伪共享</font><br>
longAccumulator
LongAccumulator
指令重排序
JVM能够根据处理器的特性(CPU的多级缓存系统、多核处理器等)适当的重新排序机器指令,使机器指令更符合CPU的执行特点,<br>最大限度的发挥机器的性能。
<b><font color="#0076b3">CAS</font></b>操作<br>Compare and Swap
CAS有3个操作数,内存值V,旧的预期值A,要修改的新值B。<br>当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则什么都不做
Unsafe.compareAndSwapInt
非阻塞算法 <br>(nonblocking algorithms)
一个线程的失败或者挂起不应该影响其他线程的失败或挂起的算法。
ABA问题
加版本号
AtomicStampedReference
一般CPU在进行线程的上下文切换的时间比执行CPU的指令集的时间长,所以CAS操作在性能上有很大的提升。<br><br>在执行CAS的操作中,没有更新成功的就会自旋,这样也会消耗CPU的资源,对于CPU来说是不友好的。
锁机制
<b><font color="#c41230">synchronized</font></b>
锁的是对象,不是代码
获取对象锁
同步代码块,锁是小括号()中的实例对象
同步非静态方法,锁是当前对象的实例对象
获取类锁
同步代码块(synchronized(类.class)),锁是类对象
同步静态方法
底层实现原理
对象头MarkWord
Java内部锁机制Monitor
字节码指令
monitorenter
monitorexit
同步方法 ACC_SYNCHRONIZED
Owner
锁池EntryList
等待池WaitSet
四种状态
锁膨胀方向:无锁 -> 偏向锁->轻量级锁->重量级锁
锁的内存语义
当线程释放锁时,Java内存模型会把该线程对应的本地内存中的共享变量刷新到主内存中<br>而当线程获取锁时,Java内存模型会把该线程对应的本地内存置为无效,从而使得被监视器保护的临界区代码必须从主内存中读取共享变量
<b>并发基石<br><font color="#0076b3">AQS</font></b>
volatile int state(代表共享资源)
FIFO线程等待队列(多线程争用资源被阻塞时会进入此队列)
<b><font color="#0076b3">LockSupport</font></b>
阻塞线程:<b><font color="#0076b3">part()</font></b>
唤醒线程:<b><font color="#0076b3">unpart(Thread thread)</font></b>
两种资源<br>共享方式
<b><font color="#0076b3">Exclusive</font></b>(独占,<br>只有一个线程能执行,<br>如<font color="#0076b3">ReentrantLock</font>)
acquire()<br>独占模式下线程获取共享资源的顶层入口<br>
release()<br>独占模式下线程获取共享资源的顶层入口<br>
<b><font color="#0076b3">Share</font></b>(共享,多个线程可同时执行,<br>如<font color="#0076b3">Semaphore</font>/<font color="#0076b3">CountDownLatch</font>)
acquireShared()
releaseShared()
<b>Lock</b>与<b>ReentrantLock</b>
加锁的原理(<font color="#0076b3">Lock.lock</font>)
非公平锁NoFairLock
公平锁FairLock
锁释放(<font color="#0076b3">Lock.unLock</font>)
条件变量(<font color="#0076b3">Condition</font>)
高级功能
等待可中断
当持有锁的线程长期不释放锁的时候,正在等待的线程可以选择放弃等待
可实现公平锁
多个线程在等待同一个锁时,必须按照申请锁的时间顺序来依次获得锁
锁可以绑定多个条件
一个ReetrantLock对象可以同时绑定多个Condition对象
共享锁
<b><font color="#0076b3">CountDownLatch</font></b><br>闭锁,倒计时器<br>
countDown
await
<font color="#0076b3"><b>CyclicBarrier</b></font><br>同步屏障<br>
await
<b><font color="#0076b3">Semaphore</font></b><br>信号量
accquire()
acquire(int permits)
tryAcquire()
tryAcquire(int permits)
release()
release(int permits)
<b><font color="#0076b3">ReentrantReadWriteLock</font></b><br>读写锁<br>
<b><font color="#0076b3">StampedLock<br></font></b>新读写锁<b><font color="#0076b3"><br></font></b>
子主题
Future
Callable
FatureTask
<b><font color="#0076b3">CompletableFuture</font></b>
可以显式完成的Future(设置其值和状态),并且可以用作CompletionStage,支持在完成时触发依赖函数和操作
创建CompletableFuture
中间组合操作
转换
thenApply、thenApplyAsync
thenCombine
组合
thenCompose
消费
thenAccept、thenAcceptAsync
thenAcceptBoth
applyToEither
运行
thenRun、 thenRunAsync
批量
allOf
anyOf
终止
handle
whenComplete
exceptionally
通过阻塞或者轮询的方式获得结果
get
getNow
join
锁的一些其他问题
线程中断机制
Exchanger
线程池
线程
<b>synchronized</b>
对象锁
类锁
Thread中的start和run的区别
Thread和Callable的区别
sleep和wait的区别
notify和notifyAll的区别
yield
会给线程调度器一个当前线程愿意让出CPU使用的暗示,但是线程调度器可能会忽略这个暗示
线程池<br>作用
减少资源消耗
通过复用池中已创建的线程,减少频繁创建、销毁线程带来的资源消耗
提高响应速度
当线程池中有空闲线程,任务到来时无需创建线程就能立即被执行
提高线程的可管理性
由线程池对池中的线程进行统一管理和监控,可防止无限制创建线程造成的资源浪费
Executor<br>ExecutorService
<b><font color="#0076b3">ThreadPoolEcecutor</font></b>
参<br>数
int <b>corePoolSize</b>
线程池核心线程数
int <b>maximumPoolSize</b>
池中的最大线程数
long <b>keepAliveTime</b>
当线程数大于corePoolSize时,多余空闲线程在终止之前等待新任务的最大时间
TimeUnit <b>unit</b>
keepAliveTime的时间单位
BlockingQueue<Runnable> <b>workQueue</b>
用于保存任务的队列,可以为无界、有界、同步移交类型的队列,这里是BlockingQueue。<br>当池子里的工作线程数大于corePoolSize时,这时新进来的任务才会放到阻塞队列中
ThreadFactory <b>threadFactory</b>
创建新线程的工厂类
RejectedExecutionHandler <b>handler</b>
队列已满且线程数达到maximunPoolSize时候的饱和策略,<br>取值有<font color="#0076b3">AbortPolicy、CallerRunsPolicy、DiscardOldestPolicy、DiscardPolicy</font>;
缓冲<br>队列
ArrayBlockingQueue
LinkedBlockingQueue
PriorityBlockingQueue
SynchronizedQueue
线程池任务拒绝策略<br><b><font color="#0076b3">RejectedExecutionHandler</font></b><br>
直接丢弃(<font color="#0076b3">DiscardPolicy</font>)
丢弃队列中最老的任务(<font color="#0076b3">DiscardOldestPolicy</font>)
抛异常(<font color="#0076b3">AbortPolicy</font>)
将任务分给调用线程来执行(<font color="#0076b3">CallerRunsPolicy</font>)
ScheduledThreadPoolExecutor
Timer<br>TimerTask
优点:简单易用
缺点:单线程串行执行
ScheduledFutureTask
DelayWrokQueue<br>带延迟的优先队列
delayedExecute<br>延迟执行任务
线程池的实现及原理
原子变量<b><font color="#0076b3">ctl</font></b>
线程池状态
运行状态 RUNNING
关闭状态 SHOTDOWN
停止状态 STOP
整理状态 TIDYING
终止状态 TERMINATED
Worker <br>工作线程,继承了AQS
execute的执行过程
addWorker<br>工作线程的创建
runWorker<br>工作线程的执行
getTask<br>任务的获取
processWorkerExit<br>工作线程的退出
shutdown<br>线程池的终止
Executors<br>线程池工具类
newSingleThreadExecutor
newCachedThreadPool
newFixedThreadPool
newScheduledThreadPool
newSingleThreadScheduledExecutor
newWorkStealingPool
Fork/Join框架
三个<br>模块<br>
1、任务对象:<b><font color="#0076b3">ForkJoinTask</font></b>
<font color="#0076b3"><b>RecursiveTask</b></font>:有返回值的任务
<b><font color="#0076b3">RecursiveAction</font></b>:无返回值的任务
2、执行Fork/Join任务的线程:<b><font color="#0076b3">ForkJoinWorkerThread</font></b>
3、线程池:<b><font color="#0076b3">ForkJoinPool</font></b>
parallelStream
适用于CPU密集型任务,默认会创建与CPU核心数相同的线程数
工作窃取(work-stealing)
线程池大小配置
需根据任务类型来配置线程池大小
CPU密集型任务:CPU数目 + 1<br>
IO密集型任务:最佳线程数目 = ((线程等待时间+线程CPU时间)/线程CPU时间 +1 )* CPU数目
通过<i><font color="#0076b3">Runtime.getRuntime().availableProcessors() </font></i>获得当前CUP个数
Executor生命周期
并发操作异常体系
并发总结
死锁
锁顺序死锁
动态的锁顺序死锁
资源死锁
死锁的四个必要条件
活跃度问题
饥饿
饥饿是指线程需要访问的资源被永久拒绝,以至于不能在继续进行
弱响应性
弱响应是指,线程最终能够得到有效的执行,只是等待的响应时间较长
活锁
活锁(Livelock)是指线程虽然没有被阻塞,但是由于某种条件不满足,一直尝试重试,却终是失败
常见的并发场景
常见的并发陷阱
性能与伸缩性
0 条评论
下一页