CountDownLatch.CyclicBarrier和 Semaphore

一  CountDownLatch

1.使用场景(与join方法类似)

   1:某一线程在开始运行前等待n个线程执行完毕。

   2:实现多个线程开始执行任务的最大并行性。强调的是多个线程在某一时刻同时开始执行。类似于赛跑,将多个线程放到起点,等待发令枪响,然后同时开跑。

2.用法

 创建

 CountDownLatch countDownLatch = new CountDownLatch(n);

    构造函数传入一个int类型的n作为计数器,你想等待n个线程完成,就传入n;

  调用await()方法时,当前线程阻塞,直到n等于0;

调用countDown()方法时,n就会减一,当n等于0时,阻塞的线程开始执行。

还有一个  await(long timeout, TimeUnit unit) 方法,指定等待的时间,当超过特定时间后,将不再阻塞当前线程。

3.内部实现

内部通过自定义一个同步器来继承同步队列,

private static final class Sync extends AbstractQueuedSynchronizer{
}

创建

public CountDownLatch(int count) {
    if (count < 0) throw new IllegalArgumentException("count < 0");
    this.sync = new Sync(count);
}

其他方法都是通过调用同步器方法来完成的。

二. CyclicBarrier

1.使用场景

 可以实现让一组线程等待至某个状态之后再全部同时执行。

2.用法

 创建

 CyclicBarrier c = new CyclicBarrier(n);  n表示屏障拦截的数量

 CyclicBarrier(int parties, Runnable barrierAction) 表示当所有线程到达屏障,准备开始运行时,优先执行barrierAction所对应的任务。
await()方法表示,告诉CyclicBarrier我已经到达了屏障,然后当前线程被阻塞,然后内部计数器加1。
当内部计数器的数值等于n时,所有被阻塞的线程全部开始运行。
await(long timeout, TimeUnit unit)
让这些线程等待至一定的时间,如果还有线程没有到达barrier状态就直接让到达barrier的线程执行后续任务。

三.Semaphore

1.使用场景

用来控制对特定资源的访问,比如数据库连接池。

2.用法

Semaphore(int permits) permits表示最大的资源访问量,可以理解为许可证总量。
Semaphore(int permits, boolean fair)。可以通过设置fair字段来完成公平锁与非公平锁的设置。
acquire()方法表示,当前线程拿走了一个许可证,总的许可证数量减1,可用资源访问量减1.

 release()方法表示,当前线程释放了一个许可证,总的许可证数量加1.  在释放许可之前,必须先获获得许可。

关于公平锁与非公平锁。当没有许可证可以获取时,调用acquire()方法的线程堵塞,并加入FIFO(双向)队列。当有线程释放许可证时,如果是公平锁,则时间上先获取许可证(即先调用acquire()方法)的线程会先获取到许可证。

而对于非公平锁,所有在队列中阻塞的线程,会用抢占式的方法来获取许可证,可以减少线程切换,提高并发量。

3.内部实现

内部也是自定义同步器来继承同步队列(AQS)

abstract static class Sync extends AbstractQueuedSynchronizer { }

总结

1)CountDownLatch和CyclicBarrier都能够实现线程之间的等待,只不过它们侧重点不同:

CountDownLatch一般用于某个线程A等待若干个其他线程执行完任务之后,它才执行;

而CyclicBarrier一般用于一组线程互相等待至某个状态,然后这一组线程再同时执行;

另外,CountDownLatch是不能够重用的,内部是通过计数器减的方式,当到达0时释放所有等待线程,无法重置。

而CyclicBarrier是可以重用的,内部通过计数器加的方式,当到达指定数量时,释放所有等待线程,可以通过调用reset()重置。

2)Semaphore其实和锁有点类似,它一般用于控制对某组资源的访问权限。

猜你喜欢

转载自blog.csdn.net/qq_36647176/article/details/85228596