JDK
2020-04-25 13:42:13 0 举报
JUC相关流程
作者其他创作
大纲/内容
是
1.只要有读锁或写锁被占用,这次就不能获取到写锁2.如果写锁获取不需要 block,那么进行 CAS,成功就代表获取到了写锁
获取锁成功返回
未中断
timed = allowCoreThreadTimeOut || wc > corePoolSize;1是否可以关闭超过保活时间的线程,如果可以则将超过corePoolSize的线程全部关闭
NonfairSync#writerShouldBlock如果是非公平模式,那么 lock 的时候就可以直接用 CAS 去抢锁,抢不到再排队
否
new Worker(firstTask)1.如果线程池的状态正确并且此时worker的数量不大于最大阈值或者不大于核心线程数和最大线程数则会新建新的线程并将记录值加一
AQS非公平锁
Semaphore
Worker#runWorker1.利用while循环先调用最开始传入的task,然后取阻塞队列中获取任务
读写锁
AbstractQueuedSynchronizer#doAcquireShared1.这里和普通的方法差不多,都是加入阻塞队列中等待被唤醒和一直尝试获取锁
获取成功
调用者
ThreadPoolExecutor#构造器1.初始化核心线程数量,最大线程数量,工作队列,保持活跃时间,线程工厂, 决绝策略
AbstractQueuedSynchronizer#transferForSignal1.将Node节点的waitStatus置为02.将Node节点加入获取锁的队列末尾
WriteLock#unlock1.和普通的释放锁相同
ThreadPoolExecutor#submit1.执行任务,返回Future对象
ReadLock#unlock1.释放读锁
getState() == 0
AbstractQueuedSynchronizer#doReleaseShared1.唤醒下一个节点
setHeadAndPropagate1.这个方法中将自己设置为头节点2.如果自己的下一个节点正在获取读锁,则释放自身的读锁并唤醒下一个节点来获取读锁
失败
new Thread(futureTask).start()1.启动一个新的线程执行FutureTask
Sync#构造器
ThreadPoolExecutor#tryTerminate1.改变线程池的状态,先更改为TIDYING然后线程执行完毕后更改为TERMINATED
ConditionObject#await1.创建Condition的Node2.释放锁,并阻塞线程3.加入锁队列获取锁
Syn#tryReleaseShared1.将当前的state-1
FutureTask#set1.利用CAS将state设置为COMPLETING状态2.将outcome赋值callable的结果3.再利用CAS将state设置为NORMAL状态
AbstractQueuedSynchronizer#acquire1.获取写锁的逻辑
Semaphore.Syn#tryReleaseShared1.释放线程
Runnable
AbstractQueuedSynchronizer#acquireSharedInterruptibly1.获取共享锁
CountDownLatch#构造器
exclusiveCount(c) != 0 &&getExclusiveOwnerThread() != current1.如果读锁的数量为0并且占用线程不是当前线程则返回
Semaphore#acquire
CyclicBarrier#nextGeneration1.还原count2.唤醒等待的线程
largestPoolSize = s;1.记录最大线程数
AbstractQueuedSynchronizer#parkAndCheckInterrupt1.将此时的线程放入等待队列
LockSupport.park(this);1.挂起当前线程
CountDownLatch#countDown
AbstractQueuedSynchronizer#unparkSuccessor1.将下一个节点唤醒
释放成功退出
FutureTask#构造器1.给callable赋值2.给state赋值NEW状态
释放失败
node.predecessor() == head&& tryAcquire(arg)
ReentrantLock#tryAcquire1.尝试获取锁
ReentrantLock#lock1.请求锁
ReentrantLock#unlock1.释放锁
ConditionObject#signal1.将线程唤醒
state == 0
FairSync#writerShouldBlock如果是公平模式,那么如果阻塞队列有线程等待的话,就乖乖去排队
AbstractQueuedSynchronizer#acquire1.进行获取锁的判断
AQS公平锁
AbstractQueuedSynchronizer#releaseShared1.释放锁的逻辑
AbstractQueuedSynchronizer#doAcquireSharedInterruptibly1.加入阻塞队列等待获取锁
继续for循环
!isOnSyncQueue1.死循环判断是否在获取锁的队列中
CyclicBarrier
AbstractQueuedSynchronizer#setState1.设置当前的state
Worker#run1.线程启动调用
head != null && head.waitStatus != 0
NonfairSync#tryAcquireShared1.尝试是否可以获取成功2.新加入的线程也可以尝试获取所以是不公平锁
ConditionObject#addConditionWaiter1.创建Node节点加到阻塞队列末尾
shouldParkAfterFailedAcquire1.将本节点的前置节点的waitStatus - > Node.SIGNAL
在释放锁的时候会唤醒挂起的线程
FairSync#tryAcquireShared1.如果阻塞队列有节点就不可以获取
ThreadPoolExecutor#drainQueue1.将所有的任务从阻塞队列中移除
nanos > 0L
Syn#tryAcquire
Unsafe#park1.调用的本地方法来挂起线程
此时当前线程已经获取锁
ConditionObject#signalAll1.将全部线程唤醒
成功
CyclicBarrier#dowait1.主要实现逻辑,利用了Lock和Condition
FairSync#lock1.这里进行一个判断
Sync#tryRelease1.释放锁的主要方法
Unsafe#unpark1.调用的本地方法来唤醒线程
Syn#tryReleaseShared1.尝试释放锁
ReadLock#lock1.获取读锁
Thread.interrupted()
AbstractQueuedSynchronizer#releaseShared1.释放共享锁
CountDownLatch#awit
ConditionObject#doSignalAll1.处理阻塞队列中的全部节点
从线程
CyclicBarrier#构造器this.parties = parties;this.count = parties; this.barrierCommand = barrierAction;1.记录数量
AbstractQueuedSynchronizer#acquireQueued1.获取锁的逻辑
FutureTask#report1.如果此时状态为NORMAL则返回调用的结果2.如果状态大于等于CANCELLED在抛出异常
Syn#tryAcquireShared1.先尝试获取锁
ThreadPoolExecutor#getTask1.这里进行获取队列中的任务操作2.根据每个阻塞队列的不同有不同的操作
中断
Future
CyclicBarrier#breakBarrier1.还原count2.唤醒等待的线程3.broken标志为true
如果成功,任务会被添加到任务队列
WriteLock#lock1.获取写锁
主线程
FutureTask#run1.利用CAS将runner赋值为执行的线程2.回调callable的call方法
Semaphore#release
唤醒
(wc > maximumPoolSize || (timed && timedOut)) && (wc > 1 || workQueue.isEmpty())compareAndDecrementWorkerCount(c)return null;1.如果超时并且阻塞队列没有任务则返回为空,关闭线程
FutureTask#get
state-acquires >= 0
ThreadPoolExecutor#shutdown1.关闭线程池,但是会执行完阻塞队列中的任务
AbstractQueuedSynchronizer#fullyRelease1.释放锁
ReentrantLock#构造器1.创建ReentrantLock对象默认使用非公平锁
不同作用线程池的创建都是基于ThreadPoolExecutor创建的,作用不同的原因是传入其中构造器参数的不同导致功能不同
线程池
AbstractQueuedSynchronizer#acquireShared1.获取读锁的逻辑
1.如果是第一次获取读锁则更新firstReader2.如果不是则获取ThreadLocal储存的对象增加本线程获取读锁的数量
t.start();1.启动worker内的线程
FutureTask#get1.阻塞直到有结果返回
isRunning(c) && workQueue.offer(command)1.线程池是否在运行并且将任务添加到阻塞队列中是否成功
ReentrantLock#nonfairTryAcquire1.尝试获取锁
AbstractQueuedSynchronizer#acquireQueued1.加入到阻塞队列
NonfairSync#lock1.这里进行一个判断
trip.await()1.挂起线程
ThreadPoolExecutor#advanceRunState1.改变线程池的状态,一个更改为SHUTDOWN一个更改为STOP
AbstractQueuedSynchronizer#hasQueuedPredecessors1.在尝试获取锁中新入的线程会调用其中的这个方法,这个方法是主要关键所在,非公平锁新入的线程则可以先尝试获取锁,如果失败了再排队
完全释放
Worker#构造器this.thread = getThreadFactory().newThread(this);1.将worker本身作为一个Runnable新建线程
--count == 0
Syn#fullTryAcquireShared1. 刚刚我们说了可能是因为 CAS 失败,如果就此返回,那么就要进入到阻塞队列了,想想有点不甘心,因为都已经满足了 !readerShouldBlock(),也就是说本来可以不用到阻塞队列的,所以进到这个方法其实是增加 CAS 成功的机会2. 在 NonFairSync 情况下,虽然 head.next 是获取写锁的,我知道它等待很久了,我没想和它抢,可是如果我是来重入读锁的,那么只能表示对不起了
CyclicBarrier#await
state <= COMPLETING
LockSupport#unpark
AbstractQueuedSynchronizer#release
Condition
ConditionObject#doSignal1.处理阻塞队列中的第一个节点
workerCountOf(c) < corePoolSize1.当前worker执行的数量和核心线程池的数量对比
AbstractQueuedSynchronizer#acquireQueued1.利用死循环查看当前节点的前置节点是不是head节点,如果是尝试获取锁,获取成功则返回
!timed
AbstractOwnableSynchronizer#setExclusiveOwnerThread1.此时获取锁,并更新锁中的独占线程变量为当前线程
FairSync# readerShouldBlock1.也就是说,公平模式下,有人在排队呢,你新来的不能直接获取锁
Semaphore#构造器
未设置超时
CountDownLatch
LockSupport#park
这个方法里回去释放锁,更新state,只有当nextc == 0 的时候代表没有任何锁则唤醒下一个节点
trip.awaitNanos(nanos)1.挂起线程
这里将state一分为2,高16位表示读锁的获取次数,后16位表示写锁的重入次数
ThreadPoolExecutor#exectue1.执行任务
ThreadPoolExecutor#shutdownNow1.关闭线程池,立即结束阻塞队列中的任务
NonFairSync#readerShouldBlock作者给写锁定义了更高的优先级,所以如果碰上获取写锁的线程马上就要获取到锁了,获取读锁的线程不应该和它抢。如果 head.next 不是来获取写锁的,那么可以随便抢
LockSupport
FutureTask#awaitDone这里进行死循环来做些特定的处理1.如果状态为COMPLETING则挂起线程2.新建一个WaitNode节点3.将节点加入到waiters中组成链表4.将线程阻塞
设置超时
启动线程
Syn#tryAcquireShared尝试获取锁
AbstractQueuedSynchronizer#addWaiter1.新建一个Node对象,将代表当前线程的Node对象放入waiter链表的尾节点
FutureTask#finishCompletion1.遍历所有的WaitNode节点2.将所有WaitNode节点阻塞的线程全部唤醒
0 条评论
下一页