概念:CountDownLatch允许一个或者多个线程等待其他线程完成操作。
CountDownLatch主要方法:
await() 使当前线程进入等待队列等待,当latch减为0或中断时,线程被唤醒。
await(long timeout, TimeUnit unit) 设置超时时间。
countDown() 使latch值减1,为0时唤醒。
getCount() 获取latch值。
CountDownLatch简单使用:
package com.Test;
/*
作者:阳小江
*/
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.locks.ReentrantLock;
public class Cas {
public static void main(String [] args)throws InterruptedException{
CountDownLatch count=new CountDownLatch(3);
WaitThread waitThread1=new WaitThread("等待线程1",count);
WaitThread waitThread2=new WaitThread("等待线程2",count);
Worker worker1=new Worker("工作线程1",count);
Worker worker2=new Worker("工作线程2",count);
Worker worker3=new Worker("工作线程3",count);
waitThread1.start();
waitThread2.start();
Thread.sleep(1000);
worker1.start();
worker2.start();
worker3.start();
}
}
class WaitThread extends Thread{
private String name;
private CountDownLatch count;
public WaitThread(String name,CountDownLatch count){
this.count=count;
this.name=name;
}
@Override
public void run() {
try {
System.out.println(this.name+"等待中");
count.await();
System.out.println(this.name+"运行");
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
class Worker extends Thread {
private String name;
private CountDownLatch count;
public Worker(String name,CountDownLatch count){
this.count=count;
this.name=name;
}
@Override
public void run() {
System.out.println(this.name+"开始运行");
try {
Thread.sleep(2);
}catch (InterruptedException e){
e.printStackTrace();
}
System.out.println(this.name+"运行结束");
count.countDown();
}
}
结果:

查看源码后理解:
CountDownLatch通过内部类Sync来实现同步
Sync继承AQS
其中 tryAcquireShared 和 tryReleaseShared 分别为获取和释放同步状态
源码如下:
`
protected int tryAcquireShared(int acquires) {
return (getState() == 0) ? 1 : -1; }
protected boolean tryReleaseShared(int releases) {
// Decrement count; signal when transition to zero
for (;;) {
int c = getState();
// 如果同步状态的值已经是0了,不要再释放同步状态了,也不要减1了
if (c == 0)
return false;
// 减1
int nextc = c - 1;
if (compareAndSetState(c, nextc))
return nextc == 0;
}
}
await()
源码中首先调用AQS的acquireSharedInterruptibly(int arg)方法
判断是否被中断,否则 尝试获取同步状态,
protected int tryAcquireShared(int acquires) {
return (getState() == 0) ? 1 : -1; }
State为0,则获取成功。
否则通过自旋AQS 的 docquireSharedInterruptibly(int arg) 挂起
将线程加入队列的尾部,然后自旋判断该节点前一个节点是否为头节点,是则尝试获取同步状态,成功则设置该节点为头节点,
前一个节点不是头节点则挂起。
countDown()
public void countDown() {
sync.releaseShared(1);
}
调用AQS的releaseShared(1)方法
public final boolean releaseShared(int arg) {
// 尝试释放同步状态
if (tryReleaseShared(arg)) {
// 如果成功,进入自旋,尝试唤醒同步队列中头结点的后继节点
doReleaseShared();
return true;
}
return false;
}
成功后调用doReleaseShared()方法,获取头节点的状态,不为空且为SIGBNAL 通过unparSUccessor()方法唤醒后续节点。
释放所有调用await()等待的线程
唤醒一个节点时,设置该节点为头节点,获取该节点下一个节点,调用doReleaseShare()唤醒线程,唤醒后设置为头节点。
if (h == head)
break;
}
每次循环后判断head头节点是否改变,没有则退出循环。

436

被折叠的 条评论
为什么被折叠?



