CountDownLatch
构造方法
它在初始化时候,可以通过构造函数新建一个类似于计数器的功能。
public CountDownLatch(int count) {
if (count < 0) throw new IllegalArgumentException("count < 0");
this.sync = new Sync(count);
}
应用场景:
几个线程在执行多个或者一个任务A后,需要一起开始执行后续的任务B。那么用CountDownLatch,可以很好的帮助实现该功能。
每当有一个线程完成任务,就调用countDown,将计数器减1。
public void countDown() {
sync.releaseShared(1);
}
已经执行完A的线程,调用await()方法,等待其他计数器的值变0,也就是其他线程执行完毕。
public void await() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
代码使用:
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class StopThread {
private static boolean stopRequested;
public static void main(String[] args) throws InterruptedException {
final CountDownLatch countDownLatch = new CountDownLatch(4);
ExecutorService executorService = Executors.newFixedThreadPool(4);
for(int i = 0;i<4;i++){
executorService.execute(new Runnable(){
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"is coming");
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"is running");
countDownLatch.countDown();
System.out.println(Thread.currentThread().getName()+"is waiting for the other");
try {
countDownLatch.await();
System.out.println(Thread.currentThread().getName()+"after countDownlatch ");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}
System.out.println(Thread.currentThread().getName()+"outer for circle");
}
}
执行结果:
mainouter for circle
pool-1-thread-3is coming
pool-1-thread-2is coming
pool-1-thread-1is coming
pool-1-thread-4is coming
pool-1-thread-3is running
pool-1-thread-2is running
pool-1-thread-1is running
pool-1-thread-2is waiting for the other
pool-1-thread-3is waiting for the other
pool-1-thread-1is waiting for the other
pool-1-thread-4is running
pool-1-thread-4is waiting for the other
pool-1-thread-3after countDownlatch
pool-1-thread-1after countDownlatch
pool-1-thread-2after countDownlatch
pool-1-thread-4after countDownlatch
源码分析:
CountDownLatch的构造函数(采用的是一种公平锁机制)
CountDownLatch的函数列表
void await():如果当前count大于0,当前线程将会wait,直到count等于0或者中断。PS:当count等于0的时候,再去调用await(),
线程将不会阻塞,而是立即运行。后面可以通过源码分析得到。
boolean await(long timeout, TimeUnit unit):使当前线程在锁存器倒计数至零之前一直等待,除非线程被中断或超出了指定的等待时间。
void countDown(): 递减锁存器的计数,如果计数到达零,则释放所有等待的线程。
long getCount() :获得计数的数量 //用于debug或者test
String toString() : return super.toString() + "[Count = " + sync.getCount() + "]";
CountDownLatch的数据结构:
await()的分析
AQS:acquireSharedInterruptibly(int arg)
CountDownLatch$Sync:int tryAcquireShared(int acquires)
如果获取共享锁继续调用doAcquireSharedInterruptibly(arg)
如果这里多个线程wait之间没有调用countDown(),线程都在等待。如下图:
setHeadAndPropagate(Node node, int propagate)
isShared()
释放共享锁,通知后面的节点。
compareAndSetWaitStatus(Node,int,int)
看 j vm的代码 hotspot-9646293b9637\src\share\vm\runtime unsafe.cpp
c++:comapreAndSwapInt
atomic.cpp
c++:cmpxchg 根据(update参数来看)代码应该赋值后在比较,但是while比较之后会再一次赋值。
countDown()分析
boolean releaseShared(int arg)
tryReleaseShared(int)