CyclicBarrier(循环屏障):当多个线程同时执行时,在某个步骤完成时,需要互相等待共同完成,然后在执行时,就可以使用该类.该类的作用就是会实现多个类达到一起行动的作用.
1,构造器:该类有两个构造器,第一个参数是设置有多少条线程数需要等待,然后共同达到某个等待点,第二个参数是传入一个Runnable,当第一个线程到达屏障点的时候,会先执行该接口里的run方法,在后面会在源码里说明.
主要使用方法:await(),里面执行的dowait()
private int dowait(boolean timed, long nanos) throws InterruptedException, BrokenBarrierException, TimeoutException { final ReentrantLock lock = this.lock; lock.lock(); try { final Generation g = generation; //初始值broken是false if (g.broken) throw new BrokenBarrierException(); //如果该线程被中断过则抛出异常 if (Thread.interrupted()) { breakBarrier(); throw new InterruptedException(); } //count是计数器,是传入的同步的线程数 int index = --count;
//当计数为0时,则先执行Runable接口的方法,然后唤醒所有线程,同时也说明所有线程都到达屏障点了,执行里面唤醒线程的方法 if (index == 0) { // tripped boolean ranAction = false; try { final Runnable command = barrierCommand; if (command != null) command.run(); ranAction = true;
//该方法会唤醒所有等待的线程,重置generation变量,使得后面还能继续设置屏障 nextGeneration(); return 0; } finally { if (!ranAction)
//该方法会终止屏障,唤醒在屏障出等待的线程 breakBarrier(); } } // loop until tripped, broken, interrupted, or timed out
//通过自旋锁实现线程在屏障出等待的功能 for (;;) { try { if (!timed)
//condition的wait方法使得调用的线程进入等待状态 trip.await(); else if (nanos > 0L) nanos = trip.awaitNanos(nanos); } catch (InterruptedException ie) { if (g == generation && ! g.broken) { breakBarrier(); throw ie; } else { // We're about to finish waiting even if we had not // been interrupted, so this interrupt is deemed to // "belong" to subsequent execution. Thread.currentThread().interrupt(); } } //判断是否被中断屏蔽,是的抛出异常 if (g.broken) throw new BrokenBarrierException(); //判断是否被通知屏蔽结束,所有线程都到达屏障点了 if (g != generation) return index; //如果设定时间了,判断是否超时 if (timed && nanos <= 0L) { breakBarrier(); throw new TimeoutException(); } } } finally { lock.unlock(); } }
通过对该方法的分析,大体知道该类的实现原理了.
案例:
import java.util.concurrent.CyclicBarrier; class CyclicBarrierDemo { /** * CyclicBarrier:关卡 * 它约束多线程必需同时达到某时刻,同时向下执行,在没有达到之前保持等待 * 比如:周末约定去爬山,在公司门口集合,必须要等所有人都到后大家在一起出发。 */ static void test(int threadNum) { // CyclicBarrier cyclicBarrier = new CyclicBarrier(3); // 构造方法可支持一个Runnable,用于在所有线程都达到后首先执行。 final CyclicBarrier cyclicBarrier = new CyclicBarrier(3, new Runnable() { @Override public void run() { System.out.println("都准备好了!"); } }); for (int i = 0; i < threadNum; i++) { new Thread(new Runnable() { @Override public void run() { try { System.out.println("线程" + Thread.currentThread().getName() + " 已经准备好."); cyclicBarrier.await(); Thread.sleep((long) (Math.random() * 2000)); System.out.println("线程" + Thread.currentThread().getName() + " 处理完毕,汇报结果!"); } catch (Exception e) {} } }).start(); } } } public class Test { public static void main(String[] args) { CyclicBarrierDemo.test(3); } }
CountDownLatch:该类和CyclicBarrier类功能类似,都是设置屏障使多个线程达到在某个点后,互相等待,都到达时在唤醒其他等待线程,共同执行下面的业务逻辑.但是该类能设置一次屏障.举例:比如有一个任务A,它要等待其他4个任务执行完毕之后才能执行,此时就可以利用CountDownLatch来实现这种功能了。
1构造器:传入的参数是计数器,显示要等待多少个线程执行完任务
2主要方法:
public void await() throws InterruptedException { }; //调用await()方法的线程会被挂起,它会等待直到count值为0才继续执行 public boolean await(long timeout, TimeUnit unit) throws InterruptedException { }; //和await()类似,只不过等待一定的时间后count值还没变为0的话就会继续执行 public void countDown() { }; //将count值减1
案例:
public class Test { public static void main(String[] args) { final CountDownLatch latch = new CountDownLatch(2); new Thread(){ public void run() { try { System.out.println("子线程"+Thread.currentThread().getName()+"正在执行"); Thread.sleep(3000); System.out.println("子线程"+Thread.currentThread().getName()+"执行完毕"); latch.countDown(); } catch (InterruptedException e) { e.printStackTrace(); } }; }.start(); new Thread(){ public void run() { try { System.out.println("子线程"+Thread.currentThread().getName()+"正在执行"); Thread.sleep(3000); System.out.println("子线程"+Thread.currentThread().getName()+"执行完毕"); latch.countDown(); } catch (InterruptedException e) { e.printStackTrace(); } }; }.start(); try { System.out.println("等待2个子线程执行完毕..."); latch.await(); System.out.println("2个子线程已经执行完毕"); System.out.println("继续执行主线程"); } catch (InterruptedException e) { e.printStackTrace(); } } }
总结:从两个案例中还是可以看出两个的用途还有区别的,一个可以多次设置屏障等待,一个值能一次.而CountDownLatch主要是针对指定线程,去等待其他先,CyclicBarrier是多个线程没有指定线程,哪个线程先到屏障点,该线程就先等待,当所有线程都完成了,那在唤醒等待线程去继续运行
两个类主要的方法都使用的是AQS类里面的方法.以后可详细说明,待后面学习.