jdk-CyclicBarrier这一篇主要是分析了它 的源码和运行图。这一篇来看看怎么运用,毕竟都是要使用的。
上文在分析源码过程中发现有个代数的问题,在nextGeneration中会有下一代的出现,这个是否就是说它是可以重用的?不然哪会来区分一代,二代,三代呢?
例子1:次例子中重复使用了CyclicBarrier
public class TestCycB {
private static int num = 3;
public static void main(String[] args) throws Exception{
final CyclicBarrier cb = new CyclicBarrier(num);
for(int i = 0; i < 3; i ++){
new EachThread(cb).start();
}
Thread.sleep(10000);
System.out.println("主线程休息够了,燥起来");
for(int i = 0; i < 3; i ++){
new EachThread(cb).start();
}
}
}
class EachThread extends Thread{
private CyclicBarrier cb;
public EachThread(CyclicBarrier cb){
this.cb = cb;
}
@Override
public void run() {
try{
Thread.sleep(2000);
System.out.println(Thread.currentThread().getName()+"进入等待");
cb.await();
Thread.sleep(2000);
System.out.println(Thread.currentThread().getName()+"等待结束了,执行起来");
}catch (InterruptedException e){
e.printStackTrace();
}catch (BrokenBarrierException e1){
e1.printStackTrace();
}
}
}
Thread-0进入等待
Thread-2进入等待
Thread-1进入等待
Thread-1等待结束了,执行起来
Thread-0等待结束了,执行起来
Thread-2等待结束了,执行起来
主线程执行
Thread-3进入等待
Thread-5进入等待
Thread-4进入等待
Thread-4等待结束了,执行起来
Thread-3等待结束了,执行起来
Thread-5等待结束了,执行起来
例子2,使用timeout,timeout是指虽然全部线程没有完全进入,但是超过这个超时时间的话,立马执行其余线程,这些线程会抛出异常,然后继续执行.
public class TestCycB {
private static int num = 3;
public static void main(String[] args) throws Exception{
final CyclicBarrier cb = new CyclicBarrier(num);
for(int i = 0; i < 3; i ++){
Thread.sleep(3000);
new EachThread(cb).start();
}
}
}
class EachThread extends Thread{
private CyclicBarrier cb;
public EachThread(CyclicBarrier cb){
this.cb = cb;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"进入初始化");
try{
Thread.sleep(2000);//模拟初始化
System.out.println(Thread.currentThread().getName() + "初始化结束,进入等待");
cb.await(3, TimeUnit.SECONDS); //睡3
}catch (InterruptedException e){
e.printStackTrace();
}catch (BrokenBarrierException e1){
e1.printStackTrace();
}catch (TimeoutException e2){
e2.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"等待结束了,执行起来");
}
}
Thread-0进入初始化
Thread-0初始化结束,进入等待
Thread-1进入初始化
java.util.concurrent.TimeoutException
Thread-1初始化结束,进入等待
at java.util.concurrent.CyclicBarrier.dowait(CyclicBarrier.java:250)
Thread-0等待结束了,执行起来
at java.util.concurrent.CyclicBarrier.await(CyclicBarrier.java:427)
Thread-1等待结束了,执行起来
at concurrenttest.EachThread.run(TestCycB.java:40)
java.util.concurrent.BrokenBarrierException
at java.util.concurrent.CyclicBarrier.dowait(CyclicBarrier.java:243)
at java.util.concurrent.CyclicBarrier.await(CyclicBarrier.java:427)
at concurrenttest.EachThread.run(TestCycB.java:40)
Thread-2进入初始化
java.util.concurrent.BrokenBarrierException
at java.util.concurrent.CyclicBarrier.dowait(CyclicBarrier.java:200)
at java.util.concurrent.CyclicBarrier.await(CyclicBarrier.java:427)
at concurrenttest.EachThread.run(TestCycB.java:40)
Thread-2初始化结束,进入等待
Thread-2等待结束了,执行起来
例子3,自定义任务,自定义任务的执行是由最终进入的线程执行的,源码中可以看见,并且这个任务是优先于其他等待线程.
public class TestCycB {
private static int num = 3;
public static void main(String[] args) throws Exception{
final CyclicBarrier cb = new CyclicBarrier(num,new Runnable() {
@Override
public void run() {
try{
Thread.sleep(5000);
}catch (Exception e){
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"自带任务的执行");
}
});
for(int i = 0; i < 3; i ++){
new EachThread(cb).start();
}
}
}
class EachThread extends Thread{
private CyclicBarrier cb;
public EachThread(CyclicBarrier cb){
this.cb = cb;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"进入初始化");
try{
Thread.sleep(2000);//模拟初始化
System.out.println(Thread.currentThread().getName() + "初始化结束,进入等待");
cb.await();
}catch (InterruptedException e){
e.printStackTrace();
}catch (BrokenBarrierException e1){
e1.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"等待结束了,执行起来");
}
}
Thread-0进入初始化
Thread-2进入初始化
Thread-1进入初始化
Thread-0初始化结束,进入等待
Thread-2初始化结束,进入等待
Thread-1初始化结束,进入等待
Thread-2自带任务的执行
Thread-0等待结束了,执行起来
Thread-1等待结束了,执行起来
Thread-2等待结束了,执行起来
例子4: 可以发现自带任务先执行完,最后才指向其他任务。
public class TestCycB {
private static int num = 3;
public static void main(String[] args) throws Exception{
final CyclicBarrier cb = new CyclicBarrier(num,new Runnable() {
@Override
public void run() {
try{
Thread.sleep(10000);
}catch (Exception e){
e.printStackTrace();
}
System.out.println("自带任务执行了");
}
});
for(int i = 0; i < 3; i ++){
new EachThread(cb).start();
}
}
}
class EachThread extends Thread{
private CyclicBarrier cb;
public EachThread(CyclicBarrier cb){
this.cb = cb;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"进入初始化");
try{
System.out.println(Thread.currentThread().getName() + "初始化结束,进入等待");
cb.await(1, TimeUnit.SECONDS); //睡3
}catch (InterruptedException e){
e.printStackTrace();
}catch (BrokenBarrierException e1){
e1.printStackTrace();
}catch (TimeoutException e2){
e2.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"等待结束了,执行起来");
}
}
Thread-2进入初始化
Thread-2初始化结束,进入等待
Thread-1进入初始化
Thread-1初始化结束,进入等待
Thread-0进入初始化
Thread-0初始化结束,进入等待
自带任务执行了
Thread-0等待结束了,执行起来
Thread-2等待结束了,执行起来
Thread-1等待结束了,执行起来
public class TestCycB {
private static int num = 3;
public static void main(String[] args) throws Exception{
final CyclicBarrier cb = new CyclicBarrier(num,new Runnable() {
@Override
public void run() {
try{
Thread.sleep(6000);
System.out.println("自带任务执行了:抛异常");
int j = 1 /0;
}catch (Exception e){
e.printStackTrace();
}
}
});
for(int i = 0; i < 3; i ++){
new EachThread(cb).start();
}
}
}
class EachThread extends Thread{
private CyclicBarrier cb;
public EachThread(CyclicBarrier cb){
this.cb = cb;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"进入初始化");
try{
Thread.sleep(2000);
System.out.println(Thread.currentThread().getName() + "初始化结束,进入等待");
cb.await(); //睡3
}catch (InterruptedException e){
e.printStackTrace();
}catch (BrokenBarrierException e1){
e1.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"等待结束了,执行起来");
}
}
Thread-0进入初始化
Thread-2进入初始化
Thread-1进入初始化
Thread-2初始化结束,进入等待
Thread-0初始化结束,进入等待
Thread-1初始化结束,进入等待
自带任务执行了:抛异常
Thread-1等待结束了,执行起来
Thread-2等待结束了,执行起来
Thread-0等待结束了,执行起来
java.lang.ArithmeticException: / by zero
at concurrenttest.TestCycB$1.run(TestCycB.java:25)
at java.util.concurrent.CyclicBarrier.dowait(CyclicBarrier.java:213)
at java.util.concurrent.CyclicBarrier.await(CyclicBarrier.java:355)
at concurrenttest.EachThread.run(TestCycB.java:54)
最后来比较下CountDownLatch和CyclicBarrier的一些不同点。。
拿赛跑来说吧,这是个比较典型的例子。
场景1:5个人赛跑,还有一个裁判,当裁判说开始时,5个人起跑,当某一个人到达终点后,裁判按一下计数器,直至最后一个人到达,最后裁判才开始统计时间,得到每个人的时间。这个就是CountDownLatch的运用。
场景2:还是5个人赛跑,这一次没有裁判了,只规定如果5个人到达终点后,一起去喝酒这个就是CyclicBarrier的运用,此例子中没有说是否需要一起起跑,如果需要,可以加上CountDownLatch。
CountDownLatch就是一个线程等待其他线程都完成之后,再执行某些事情,强调这个。
CyclicBarrier强调线程互相等待,等待全部完成。