生活
代码无非是生活现实场景的翻译,把某些场景翻译成代码,即简单又复杂。
AQS中的应用也与我们的生活息息相关。
场景
今天来看一个有趣的场景,经历过学生时代的,都对那段必须跑的长跑深恶痛绝,发令枪响开跑,然后等到所有人跑完,老师才会把大家召集起来统一公布成绩。
这个场景用程序来模拟,实际就是N个线程执行操作,等全部执行完了,才执行某一个特定操作。
countDownLatch正是一个能提供如此功能的并发工具类了。
简述
CountDownLatch是JDK1.5中引入进来的,称之为闭锁,或者同步计数器等。
下面的代码告诉你如何创建一个资源数为N的闭锁。(即学生数为N的闭锁)
//此为创建闭锁的构造器
public CountDownLatch(int count) {
if (count < 0) throw new IllegalArgumentException("count < 0");
this.sync = new Sync(count);
}
注意资源数不能小于0
//此为创建闭锁的代码
//就是new对象,没啥好说的,具体this.sync=new Sync(count) 就不说了可以自己点进去看,其实归根到底还是到AQS的共享资源state
CountDownLatch latch = new CountDownLatch(5);
闭锁中使用到的两个方法如下:
计数器-1:
public void countDown() {
sync.releaseShared(1);
}
等待:
public boolean await(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
}
这个代码很简单,不明白的可以看下前面的AQS初探,借用了前辈写的东西,一步步走下去,还是很详细的哦。
案例
下面贴出使用的案例代码
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.CountDownLatch;
public class CDLTest {
public static void main(String[] args) {
CountDownLatch latch = new CountDownLatch(5);
Thread t1 = new Thread(new Student(latch, "A"));
Thread t2 = new Thread(new Student(latch, "B"));
Thread t3 = new Thread(new Student(latch, "C"));
Thread t4 = new Thread(new Student(latch, "D"));
Thread t5 = new Thread(new Student(latch, "E"));
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
try {
//等待 计数器减为0才往下走
latch.await();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("开始公布成绩。。。。。。。。。。。");
for(int i=0;i<Student.students.size();i++) {
System.out.println("第"+(i+1)+"名:"+Student.students.get(i).getName());
}
}
static class Student implements Runnable{
private CountDownLatch latch;
private String name;
public static final List<Student> students = new ArrayList<>();
@Override
public void run() {
try {
Thread.sleep(Long.valueOf(new Random().nextInt(2000)));
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("学生:"+name+",跑到终点!");
students.add(this);
//计数器-1
latch.countDown();
}
public String getName() {
return name;
}
public Student(CountDownLatch latch, String name) {
super();
this.latch = latch;
this.name = name;
}
}
}
执行得到的一次结果如下:
学生:A,跑到终点!
学生:C,跑到终点!
学生:D,跑到终点!
学生:B,跑到终点!
学生:E,跑到终点!
开始公布成绩。。。。。。。。。。。
第1名:A
第2名:C
第3名:D
第4名:B
第5名:E
注意
注意闭锁是没法重用的,用过以后这个对象就木有用了,因为没有提供对外的方法来重置AQS中的state。
后记
代码很简单,思想很牛逼,前辈写的代码要多多学习啊,哈哈,今天到这里,明天看看后面的回环栅栏。~~