Java JUC 同步辅助类 CountDownLatch , CyclicBarrier , Semaphore

线程通信 如何使用 CountDownLatch , CyclicBarrier , Semaphore 

Java JUC 同步辅助类 CountDownLatch , CyclicBarrier , Semaphore

2014年甘肃,前往桑科草原的路上,停车休息。

微信公众号

Java JUC 同步辅助类 CountDownLatch , CyclicBarrier , Semaphore

Java JUC 同步辅助类 CountDownLatch , CyclicBarrier , Semaphore

王皓的GitHub:https://github.com/TenaciousDWang

 

JUC包在JDK1.5之后加入了几个很有用的同步辅助类来帮助我们并发编程CountDownLatch,CyclicBarrier,Semaphore,我们可以直接使用,不需要自己来手动设计和编写,使用JDK提供的类和方法可以无需担心性能和安全上的问题。

 

CountDownLatch

CountDownLatch用来一个或多个线程等待其他线程执行完成后再执行,使用一个int参数来计数,开始执行时阻塞需要被阻塞的线程,其他每个线程执行后对参数减一,等归零后唤醒被阻塞的线程。

 

Java JUC 同步辅助类 CountDownLatch , CyclicBarrier , Semaphore

 

CountDownLatch源码316行,90%是注释,感兴趣的同学也可以自行查看,这里我们只看构造方法和几个主要方法我们先看一下CountDownLatch的构造方法,CountDownLatch只提供了一个构造方法。

 

Java JUC 同步辅助类 CountDownLatch , CyclicBarrier , Semaphore

 

count用来表示计数。

 

Java JUC 同步辅助类 CountDownLatch , CyclicBarrier , Semaphore

 

await()方法,调用时阻塞线程,count归零后唤醒线程。

 

Java JUC 同步辅助类 CountDownLatch , CyclicBarrier , Semaphore

 

await(long timeout, TimeUnit unit)方法,调用时阻塞线程,这时跟count没有关系了,而是时间到了不管count有没有归零都会唤醒被阻塞的线程。

 

Java JUC 同步辅助类 CountDownLatch , CyclicBarrier , Semaphore

 

countDown()方法,计数器减一。

 

Java JUC 同步辅助类 CountDownLatch , CyclicBarrier , Semaphore

 

getCount()方法,获取当前计数。

 

接下来写一个Demo来看看如何使用。

 

Java JUC 同步辅助类 CountDownLatch , CyclicBarrier , Semaphore

 

初始化CountDownLatch,计数为2,主线程执行await(),起两个线程,每个线程执行完latch.countDown()计数减一,两个线程都执行完毕后,计数归零,主线程被唤醒后继续执行。

 

执行结果为:

 

Java JUC 同步辅助类 CountDownLatch , CyclicBarrier , Semaphore

 

CyclicBarrier

 

CyclicBarrier,周期屏障,回环栏栅。。。其实就是一个Barrier屏障,假设有三个线程,他们必须都运行到一个点时才能继续向后执行,这与上面说的CountDownLatch不一样,CountDownLatch是指A线程和B线程执行完毕后唤醒C线程,CyclicBarrier相当于一个屏障,必须ABC三个线程都到达一个状态或者Barrier时,才能全部唤醒继续,有一个没有到达Barrier,那么这三个线程都会阻塞。与CountDownLatch还有一个不同是CyclicBarrier可以重复使用,接下来我们看一下CyclicBarrier的相关源码。

 

Java JUC 同步辅助类 CountDownLatch , CyclicBarrier , Semaphore

 

首先看一下CyclicBarrier的构造函数,共有两个。

 

Java JUC 同步辅助类 CountDownLatch , CyclicBarrier , Semaphore

 

第一个只需要上述需要被屏障线程的数量即可。

 

Java JUC 同步辅助类 CountDownLatch , CyclicBarrier , Semaphore

 

第二个,其实第一个构造方法调用的第二个构造方法,多出来参数Runnable barrierAction,指的是当所有线程进入barrier状态时,由最后一个进入barrier状态的线程唤醒barrierAction线程执行里面的内容,用来处理更复杂的业务,类似于CountDownLatch,然后所有线程才可以全部唤醒继续执行。

 

CyclicBarrier同CountDownLatch一样提供两个阻塞await方法。

 

Java JUC 同步辅助类 CountDownLatch , CyclicBarrier , Semaphore

 

接下来我们来写一个Demo来看一下CyclicBarrier如何使用。

 

Java JUC 同步辅助类 CountDownLatch , CyclicBarrier , Semaphore

 

我们创建三个线程,只有当三个线程都创建完毕,并执行到cyclicBarrier.await()时,三个线程才会继续执行,在这之前创建好的线程都会被挂起。我们来看一下执行结果。

 

Java JUC 同步辅助类 CountDownLatch , CyclicBarrier , Semaphore

 

接下来我们使用CyclicBarrier的第二个构造方式看一下barrierAction的使用。

 

Java JUC 同步辅助类 CountDownLatch , CyclicBarrier , Semaphore

 

我们来看一下执行结果。

 

Java JUC 同步辅助类 CountDownLatch , CyclicBarrier , Semaphore

 

这时,我们看到是又最后一个到达barrier状态的线程来执行这个Runnable。

 

接下来我们看一下await使用时间设置

 

cyclicBarrier.await(1,TimeUnit.SECONDS)

 

Java JUC 同步辅助类 CountDownLatch , CyclicBarrier , Semaphore

 

执行结果如下;

 

Java JUC 同步辅助类 CountDownLatch , CyclicBarrier , Semaphore

 

到达指定时间后,三个线程并没有都到达Barrier状态,这时每个线程会开始抛出异常并继续执行Barrier后的代码。

 

最后演示一下上面说的CyclicBarrier可以重复使用的Demo。

 

Java JUC 同步辅助类 CountDownLatch , CyclicBarrier , Semaphore

 

执行结果为:

 

Java JUC 同步辅助类 CountDownLatch , CyclicBarrier , Semaphore

 

Semaphore

 

Semaphore可以控制同时访问的线程个数,可以达到限流的目的,通过 acquire() 获取一个许可,如果没有就等待,而 release() 释放一个许可,让其他线程进入。

 

Java JUC 同步辅助类 CountDownLatch , CyclicBarrier , Semaphore

 

我们来看一下Semaphore的构造器,共有两个.

 

Java JUC 同步辅助类 CountDownLatch , CyclicBarrier , Semaphore

 

permits指许可的数量,fair是否公平,即等待时间越长可以在有许可的时候优先获取。

 

Java JUC 同步辅助类 CountDownLatch , CyclicBarrier , Semaphore

Java JUC 同步辅助类 CountDownLatch , CyclicBarrier , Semaphore

 

acquire(),获取许可,acquire(int permits)获取多个许可,如果没有许可,则会一直等待,直到获得许可。

 

Java JUC 同步辅助类 CountDownLatch , CyclicBarrier , Semaphore

Java JUC 同步辅助类 CountDownLatch , CyclicBarrier , Semaphore

 

release(),释放许可,release(int permits),释放多个许可。

 

Java JUC 同步辅助类 CountDownLatch , CyclicBarrier , Semaphore

Java JUC 同步辅助类 CountDownLatch , CyclicBarrier , Semaphore

 

tryAcquire可以尝试获取许可,如果可以获得则返回true,获取不到则返回false。

 

tryAcquire(long timeout, TimeUnit unit)在timeout时间内获取到许可则返回true。

 

tryAcquire(int permits)与tryAcquire(int permits, long timeout, TimeUnit unit)同上,添加了在timeout时间内尝试获取permits个许可。

 

最后写一个Demo来演示一下semaphore的使用。

 

一个网吧有5台机器,但是共有10个网友,只有一个网友到钟后,其他网友才能上机。那么我们就可以通过Semaphore来实现限流。

 

Java JUC 同步辅助类 CountDownLatch , CyclicBarrier , Semaphore

 

最后执行结果为:

 

Java JUC 同步辅助类 CountDownLatch , CyclicBarrier , Semaphore

 

以上。