CountDownLatch的用法
CountDownLatch类位于java.util.concurrent包下,利用它可以实现类似计数器的功能。比如有一个任务A,它要等待其他4个任务执行完毕之后才能执行,此时就可以利用CountDownLatch来实现这种功能了。
public CountDownLatch(int count) { }; //参数count为计数值
然后下面这3个方法是CountDownLatch类中最重要的方法:
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
调用await()
package com.javaedge.concurrency.example.aqs;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@Slf4j
public class CountDownLatchExample1 {
private final static int threadCount = 200;
public static void main(String[] args) throws Exception {
ExecutorService exec = Executors.newCachedThreadPool();
final CountDownLatch countDownLatch = new CountDownLatch(threadCount);
for (int i = 0; i < threadCount; i++) {
final int threadNum = i;
exec.execute(() -> {
try {
test(threadNum);
} catch (Exception e) {
log.error("exception", e);
} finally {
countDownLatch.countDown();
}
});
}
countDownLatch.await();
log.info("finish");
exec.shutdown();
}
private static void test(int threadNum) throws Exception {
Thread.sleep(100);
log.info("{}", threadNum);
Thread.sleep(100);
}
}
结果:
finish最后输出
调用await(timeout,timeunit)
package com.javaedge.concurrency.example.aqs;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
@Slf4j
public class CountDownLatchExample2 {
private final static int threadCount = 200;
public static void main(String[] args) throws Exception {
ExecutorService exec = Executors.newCachedThreadPool();
final CountDownLatch countDownLatch = new CountDownLatch(threadCount);
for (int i = 0; i < threadCount; i++) {
final int threadNum = i;
exec.execute(() -> {
try {
test(threadNum);
} catch (Exception e) {
log.error("exception", e);
} finally {
countDownLatch.countDown();
}
});
}
countDownLatch.await(10, TimeUnit.MILLISECONDS);
log.info("finish");
exec.shutdown();
}
private static void test(int threadNum) throws Exception {
Thread.sleep(100);
log.info("{}", threadNum);
}
}
结果:
finish刚开始就输出了
CyclicBarrier用法
CyclicBarrier可以被重用。当调用await()方法之后,线程就处于barrier了。等待指定数量的线程都准备完成执行后续操作。
CyclicBarrier类位于java.util.concurrent包下,CyclicBarrier提供2个构造器:
public CyclicBarrier(int parties, Runnable barrierAction) {
//Runnable中可以执行额外的操作
if (parties <= 0) throw new IllegalArgumentException();
this.parties = parties;
this.count = parties;
this.barrierCommand = barrierAction;
}
public CyclicBarrier(int parties) {
this(parties, null);
}
参数parties指让多少个线程或者任务等待至barrier状态;参数barrierAction为当这些线程都达到barrier状态时会执行的内容。
然后CyclicBarrier中最重要的方法就是await方法,它有2个重载版本:
public int await() throws InterruptedException, BrokenBarrierException {
try {
return dowait(false, 0L);
} catch (TimeoutException toe) {
throw new Error(toe); // cannot happen
}
}
public int await(long timeout, TimeUnit unit)
throws InterruptedException,
BrokenBarrierException,
TimeoutException {
return dowait(true, unit.toNanos(timeout));
}
await()当准备的线程都进入barrier状态后才会执行后续操作
await(timeout,timeunit)已进入barrier状态的线程在等待指定时间后,就会执行后续操作,
await()使用:等待给出的线程个数准备完毕,在继续执行后续操作代码如下:
package com.javaedge.concurrency.example.aqs;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@Slf4j
public class CyclicBarrierExample1 {
private static CyclicBarrier barrier = new CyclicBarrier(5);
public static void main(String[] args) throws Exception {
ExecutorService executor = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
final int threadNum = i;
Thread.sleep(1000);
executor.execute(() -> {
try {
race(threadNum);
} catch (Exception e) {
log.error("exception", e);
}
});
}
executor.shutdown();
}
private static void race(int threadNum) throws Exception {
Thread.sleep(1000);
log.info("{} is ready", threadNum);
barrier.await();
log.info("{} continue", threadNum);
}
}
执行结果
15:10:46.491 [pool-1-thread-1] INFO com.javaedge.concurrency.example.aqs.CyclicBarrierExample1 - 0 is ready
15:10:47.490 [pool-1-thread-2] INFO com.javaedge.concurrency.example.aqs.CyclicBarrierExample1 - 1 is ready
15:10:48.490 [pool-1-thread-3] INFO com.javaedge.concurrency.example.aqs.CyclicBarrierExample1 - 2 is ready
15:10:49.490 [pool-1-thread-4] INFO com.javaedge.concurrency.example.aqs.CyclicBarrierExample1 - 3 is ready
15:10:50.490 [pool-1-thread-5] INFO com.javaedge.concurrency.example.aqs.CyclicBarrierExample1 - 4 is ready
15:10:50.490 [pool-1-thread-1] INFO com.javaedge.concurrency.example.aqs.CyclicBarrierExample1 - 0 continue
15:10:50.490 [pool-1-thread-2] INFO com.javaedge.concurrency.example.aqs.CyclicBarrierExample1 - 1 continue
15:10:50.490 [pool-1-thread-3] INFO com.javaedge.concurrency.example.aqs.CyclicBarrierExample1 - 2 continue
15:10:50.490 [pool-1-thread-4] INFO com.javaedge.concurrency.example.aqs.CyclicBarrierExample1 - 3 continue
15:10:50.490 [pool-1-thread-5] INFO com.javaedge.concurrency.example.aqs.CyclicBarrierExample1 - 4 continue
15:10:51.490 [pool-1-thread-6] INFO com.javaedge.concurrency.example.aqs.CyclicBarrierExample1 - 5 is ready
15:10:52.490 [pool-1-thread-5] INFO com.javaedge.concurrency.example.aqs.CyclicBarrierExample1 - 6 is ready
15:10:53.490 [pool-1-thread-4] INFO com.javaedge.concurrency.example.aqs.CyclicBarrierExample1 - 7 is ready
15:10:54.490 [pool-1-thread-3] INFO com.javaedge.concurrency.example.aqs.CyclicBarrierExample1 - 8 is ready
15:10:55.490 [pool-1-thread-1] INFO com.javaedge.concurrency.example.aqs.CyclicBarrierExample1 - 9 is ready
15:10:55.490 [pool-1-thread-1] INFO com.javaedge.concurrency.example.aqs.CyclicBarrierExample1 - 9 continue
15:10:55.490 [pool-1-thread-6] INFO com.javaedge.concurrency.example.aqs.CyclicBarrierExample1 - 5 continue
15:10:55.490 [pool-1-thread-5] INFO com.javaedge.concurrency.example.aqs.CyclicBarrierExample1 - 6 continue
15:10:55.490 [pool-1-thread-4] INFO com.javaedge.concurrency.example.aqs.CyclicBarrierExample1 - 7 continue
15:10:55.490 [pool-1-thread-3] INFO com.javaedge.concurrency.example.aqs.CyclicBarrierExample1 - 8 continue
Process finished with exit code 0
await(timeout,timeunit)使用:等待给出的线程个数准备完毕,在继续执行后续操作代码如下:
package com.javaedge.concurrency.example.aqs;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
@Slf4j
public class CyclicBarrierExample2 {
private static CyclicBarrier barrier = new CyclicBarrier(5);
public static void main(String[] args) throws Exception {
ExecutorService executor = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
final int threadNum = i;
Thread.sleep(1000);
executor.execute(() -> {
try {
race(threadNum);
} catch (Exception e) {
log.error("exception", e);
}
});
}
executor.shutdown();
}
private static void race(int threadNum) throws Exception {
Thread.sleep(1000);
log.info("{} is ready", threadNum);
try {
barrier.await(2000, TimeUnit.MILLISECONDS);
} catch (Exception e) {
log.warn("BarrierException", e);
}
log.info("{} continue", threadNum);
}
}
执行结构:
15:15:47.581 [pool-1-thread-1] INFO com.javaedge.concurrency.example.aqs.CyclicBarrierExample2 - 0 is ready
15:15:48.580 [pool-1-thread-2] INFO com.javaedge.concurrency.example.aqs.CyclicBarrierExample2 - 1 is ready
15:15:49.580 [pool-1-thread-3] INFO com.javaedge.concurrency.example.aqs.CyclicBarrierExample2 - 2 is ready
15:15:49.587 [pool-1-thread-3] WARN com.javaedge.concurrency.example.aqs.CyclicBarrierExample2 - BarrierException
java.util.concurrent.BrokenBarrierException: null
at java.util.concurrent.CyclicBarrier.dowait(CyclicBarrier.java:250)
at java.util.concurrent.CyclicBarrier.await(CyclicBarrier.java:435)
at com.javaedge.concurrency.example.aqs.CyclicBarrierExample2.race(CyclicBarrierExample2.java:37)
at com.javaedge.concurrency.example.aqs.CyclicBarrierExample2.lambda$main$0(CyclicBarrierExample2.java:24)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
15:15:49.587 [pool-1-thread-1] WARN com.javaedge.concurrency.example.aqs.CyclicBarrierExample2 - BarrierException
java.util.concurrent.TimeoutException: null
at java.util.concurrent.CyclicBarrier.dowait(CyclicBarrier.java:257)
at java.util.concurrent.CyclicBarrier.await(CyclicBarrier.java:435)
at com.javaedge.concurrency.example.aqs.CyclicBarrierExample2.race(CyclicBarrierExample2.java:37)
at com.javaedge.concurrency.example.aqs.CyclicBarrierExample2.lambda$main$0(CyclicBarrierExample2.java:24)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
15:15:49.588 [pool-1-thread-1] INFO com.javaedge.concurrency.example.aqs.CyclicBarrierExample2 - 0 continue
15:15:49.587 [pool-1-thread-2] WARN com.javaedge.concurrency.example.aqs.CyclicBarrierExample2 - BarrierException
java.util.concurrent.BrokenBarrierException: null
at java.util.concurrent.CyclicBarrier.dowait(CyclicBarrier.java:250)
at java.util.concurrent.CyclicBarrier.await(CyclicBarrier.java:435)
at com.javaedge.concurrency.example.aqs.CyclicBarrierExample2.race(CyclicBarrierExample2.java:37)
at com.javaedge.concurrency.example.aqs.CyclicBarrierExample2.lambda$main$0(CyclicBarrierExample2.java:24)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
15:15:49.588 [pool-1-thread-3] INFO com.javaedge.concurrency.example.aqs.CyclicBarrierExample2 - 2 continue
15:15:49.588 [pool-1-thread-2] INFO com.javaedge.concurrency.example.aqs.CyclicBarrierExample2 - 1 continue
15:15:50.580 [pool-1-thread-4] INFO com.javaedge.concurrency.example.aqs.CyclicBarrierExample2 - 3 is ready
15:15:50.580 [pool-1-thread-4] WARN com.javaedge.concurrency.example.aqs.CyclicBarrierExample2 - BarrierException
java.util.concurrent.BrokenBarrierException: null
at java.util.concurrent.CyclicBarrier.dowait(CyclicBarrier.java:207)
at java.util.concurrent.CyclicBarrier.await(CyclicBarrier.java:435)
at com.javaedge.concurrency.example.aqs.CyclicBarrierExample2.race(CyclicBarrierExample2.java:37)
at com.javaedge.concurrency.example.aqs.CyclicBarrierExample2.lambda$main$0(CyclicBarrierExample2.java:24)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
15:15:50.580 [pool-1-thread-4] INFO com.javaedge.concurrency.example.aqs.CyclicBarrierExample2 - 3 continue
15:15:51.580 [pool-1-thread-2] INFO com.javaedge.concurrency.example.aqs.CyclicBarrierExample2 - 4 is ready
15:15:51.580 [pool-1-thread-2] WARN com.javaedge.concurrency.example.aqs.CyclicBarrierExample2 - BarrierException
java.util.concurrent.BrokenBarrierException: null
at java.util.concurrent.CyclicBarrier.dowait(CyclicBarrier.java:207)
at java.util.concurrent.CyclicBarrier.await(CyclicBarrier.java:435)
at com.javaedge.concurrency.example.aqs.CyclicBarrierExample2.race(CyclicBarrierExample2.java:37)
at com.javaedge.concurrency.example.aqs.CyclicBarrierExample2.lambda$main$0(CyclicBarrierExample2.java:24)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
15:15:51.580 [pool-1-thread-2] INFO com.javaedge.concurrency.example.aqs.CyclicBarrierExample2 - 4 continue
15:15:52.580 [pool-1-thread-4] INFO com.javaedge.concurrency.example.aqs.CyclicBarrierExample2 - 5 is ready
15:15:52.580 [pool-1-thread-4] WARN com.javaedge.concurrency.example.aqs.CyclicBarrierExample2 - BarrierException
java.util.concurrent.BrokenBarrierException: null
at java.util.concurrent.CyclicBarrier.dowait(CyclicBarrier.java:207)
at java.util.concurrent.CyclicBarrier.await(CyclicBarrier.java:435)
at com.javaedge.concurrency.example.aqs.CyclicBarrierExample2.race(CyclicBarrierExample2.java:37)
at com.javaedge.concurrency.example.aqs.CyclicBarrierExample2.lambda$main$0(CyclicBarrierExample2.java:24)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
15:15:52.580 [pool-1-thread-4] INFO com.javaedge.concurrency.example.aqs.CyclicBarrierExample2 - 5 continue
15:15:53.583 [pool-1-thread-2] INFO com.javaedge.concurrency.example.aqs.CyclicBarrierExample2 - 6 is ready
15:15:53.583 [pool-1-thread-2] WARN com.javaedge.concurrency.example.aqs.CyclicBarrierExample2 - BarrierException
java.util.concurrent.BrokenBarrierException: null
at java.util.concurrent.CyclicBarrier.dowait(CyclicBarrier.java:207)
at java.util.concurrent.CyclicBarrier.await(CyclicBarrier.java:435)
at com.javaedge.concurrency.example.aqs.CyclicBarrierExample2.race(CyclicBarrierExample2.java:37)
at com.javaedge.concurrency.example.aqs.CyclicBarrierExample2.lambda$main$0(CyclicBarrierExample2.java:24)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
15:15:53.583 [pool-1-thread-2] INFO com.javaedge.concurrency.example.aqs.CyclicBarrierExample2 - 6 continue
15:15:54.583 [pool-1-thread-2] INFO com.javaedge.concurrency.example.aqs.CyclicBarrierExample2 - 7 is ready
15:15:54.583 [pool-1-thread-2] WARN com.javaedge.concurrency.example.aqs.CyclicBarrierExample2 - BarrierException
java.util.concurrent.BrokenBarrierException: null
at java.util.concurrent.CyclicBarrier.dowait(CyclicBarrier.java:207)
at java.util.concurrent.CyclicBarrier.await(CyclicBarrier.java:435)
at com.javaedge.concurrency.example.aqs.CyclicBarrierExample2.race(CyclicBarrierExample2.java:37)
at com.javaedge.concurrency.example.aqs.CyclicBarrierExample2.lambda$main$0(CyclicBarrierExample2.java:24)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
15:15:54.583 [pool-1-thread-2] INFO com.javaedge.concurrency.example.aqs.CyclicBarrierExample2 - 7 continue
15:15:55.583 [pool-1-thread-2] INFO com.javaedge.concurrency.example.aqs.CyclicBarrierExample2 - 8 is ready
15:15:55.583 [pool-1-thread-2] WARN com.javaedge.concurrency.example.aqs.CyclicBarrierExample2 - BarrierException
java.util.concurrent.BrokenBarrierException: null
at java.util.concurrent.CyclicBarrier.dowait(CyclicBarrier.java:207)
at java.util.concurrent.CyclicBarrier.await(CyclicBarrier.java:435)
at com.javaedge.concurrency.example.aqs.CyclicBarrierExample2.race(CyclicBarrierExample2.java:37)
at com.javaedge.concurrency.example.aqs.CyclicBarrierExample2.lambda$main$0(CyclicBarrierExample2.java:24)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
15:15:55.583 [pool-1-thread-2] INFO com.javaedge.concurrency.example.aqs.CyclicBarrierExample2 - 8 continue
15:15:56.584 [pool-1-thread-4] INFO com.javaedge.concurrency.example.aqs.CyclicBarrierExample2 - 9 is ready
15:15:56.584 [pool-1-thread-4] WARN com.javaedge.concurrency.example.aqs.CyclicBarrierExample2 - BarrierException
java.util.concurrent.BrokenBarrierException: null
at java.util.concurrent.CyclicBarrier.dowait(CyclicBarrier.java:207)
at java.util.concurrent.CyclicBarrier.await(CyclicBarrier.java:435)
at com.javaedge.concurrency.example.aqs.CyclicBarrierExample2.race(CyclicBarrierExample2.java:37)
at com.javaedge.concurrency.example.aqs.CyclicBarrierExample2.lambda$main$0(CyclicBarrierExample2.java:24)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
15:15:56.584 [pool-1-thread-4] INFO com.javaedge.concurrency.example.aqs.CyclicBarrierExample2 - 9 continue
Process finished with exit code 0
从结果可以看出线程123进入barrier状态后,线程3等待超时并抛出异常BrokenBarrierException
后,继续执行后续
使用CyclicBarrier(N,Runnable)可以执行额外的操作,代码实例
package com.javaedge.concurrency.example.aqs;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@Slf4j
public class CyclicBarrierExample3 {
private static CyclicBarrier barrier = new CyclicBarrier(5, () -> {
log.info("callback is running");
});
//() -> {log.info("callback is running")},jdk1.8的新特性Lambda表达式,相当于实现了Runnable接口并重写了run()方法
public static void main(String[] args) throws Exception {
ExecutorService executor = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
final int threadNum = i;
Thread.sleep(1000);
executor.execute(() -> {
try {
race(threadNum);
} catch (Exception e) {
log.error("exception", e);
}
});
}
executor.shutdown();
}
private static void race(int threadNum) throws Exception {
Thread.sleep(1000);
log.info("{} is ready", threadNum);
barrier.await();
log.info("{} continue", threadNum);
}
}
执行结果
15:29:01.159 [pool-1-thread-1] INFO com.javaedge.concurrency.example.aqs.CyclicBarrierExample3 - 0 is ready
15:29:02.158 [pool-1-thread-2] INFO com.javaedge.concurrency.example.aqs.CyclicBarrierExample3 - 1 is ready
15:29:03.159 [pool-1-thread-3] INFO com.javaedge.concurrency.example.aqs.CyclicBarrierExample3 - 2 is ready
15:29:04.159 [pool-1-thread-4] INFO com.javaedge.concurrency.example.aqs.CyclicBarrierExample3 - 3 is ready
15:29:05.159 [pool-1-thread-5] INFO com.javaedge.concurrency.example.aqs.CyclicBarrierExample3 - 4 is ready
15:29:05.159 [pool-1-thread-5] INFO com.javaedge.concurrency.example.aqs.CyclicBarrierExample3 - callback is running
15:29:05.159 [pool-1-thread-5] INFO com.javaedge.concurrency.example.aqs.CyclicBarrierExample3 - 4 continue
15:29:05.159 [pool-1-thread-1] INFO com.javaedge.concurrency.example.aqs.CyclicBarrierExample3 - 0 continue
15:29:05.159 [pool-1-thread-2] INFO com.javaedge.concurrency.example.aqs.CyclicBarrierExample3 - 1 continue
15:29:05.159 [pool-1-thread-3] INFO com.javaedge.concurrency.example.aqs.CyclicBarrierExample3 - 2 continue
15:29:05.159 [pool-1-thread-4] INFO com.javaedge.concurrency.example.aqs.CyclicBarrierExample3 - 3 continue
15:29:06.159 [pool-1-thread-6] INFO com.javaedge.concurrency.example.aqs.CyclicBarrierExample3 - 5 is ready
15:29:07.159 [pool-1-thread-1] INFO com.javaedge.concurrency.example.aqs.CyclicBarrierExample3 - 6 is ready
15:29:08.159 [pool-1-thread-2] INFO com.javaedge.concurrency.example.aqs.CyclicBarrierExample3 - 7 is ready
15:29:09.159 [pool-1-thread-3] INFO com.javaedge.concurrency.example.aqs.CyclicBarrierExample3 - 8 is ready
15:29:10.159 [pool-1-thread-4] INFO com.javaedge.concurrency.example.aqs.CyclicBarrierExample3 - 9 is ready
15:29:10.159 [pool-1-thread-4] INFO com.javaedge.concurrency.example.aqs.CyclicBarrierExample3 - callback is running
15:29:10.159 [pool-1-thread-4] INFO com.javaedge.concurrency.example.aqs.CyclicBarrierExample3 - 9 continue
15:29:10.159 [pool-1-thread-2] INFO com.javaedge.concurrency.example.aqs.CyclicBarrierExample3 - 7 continue
15:29:10.159 [pool-1-thread-6] INFO com.javaedge.concurrency.example.aqs.CyclicBarrierExample3 - 5 continue
15:29:10.159 [pool-1-thread-1] INFO com.javaedge.concurrency.example.aqs.CyclicBarrierExample3 - 6 continue
15:29:10.159 [pool-1-thread-3] INFO com.javaedge.concurrency.example.aqs.CyclicBarrierExample3 - 8 continue
Process finished with exit code 0
从控制台日志中可以看出,当指定线程完成所有操作后,回调了Runnable接口的实现类中的run()方法
Semaphore的用法
Semaphore 信号量,Semaphore可以控同时访问的线程个数,通过 acquire() 获取一个许可,如果没有就等待,而 release() 释放一个许可。
Semaphore类位于java.util.concurrent包下,它提供了2个构造器:
public Semaphore(int permits) {
//参数permits表示许可数量,即同时可以有多少个线程
sync = new NonfairSync(permits);
}
public Semaphore(int permits, boolean fair) {
//fair表示是否公平的,等待时间越久的越容易获取许可
sync = fair ? new FairSync(permits) : new NonfairSync(permits);
}
其中获取许可和释放许可的方法如下:
public void acquire() throws InterruptedException { } //获取一个许可
public void acquire(int permits) throws InterruptedException { } //获取permits个许可
public void release() { } //释放一个许可
public void release(int permits) { } //释放permits个许可
acquire()用来获取一个许可,若无许可能够获得,则会一直等待,直到获得许可。
release()用来释放许可。注意,在释放许可之前,必须先获获得许可。
这4个方法都会被阻塞,如果想立即得到执行结果,可以使用下面几个方法:
public boolean tryAcquire() { }; //尝试获取一个许可,若获取成功,则立即返回true,若获取失败,则立即返回false
public boolean tryAcquire(long timeout, TimeUnit unit) throws InterruptedException { }; //尝试获取一个许可,若在指定的时间内获取成功,则立即返回true,否则则立即返回false
public boolean tryAcquire(int permits) { }; //尝试获取permits个许可,若获取成功,则立即返回true,若获取失败,则立即返回false
public boolean tryAcquire(int permits, long timeout, TimeUnit unit) throws InterruptedException { }; //尝试获取permits个许可,若在指定的时间内获取成功,则立即返回true,否则则立即返回false
另外还可以通过availablePermits()方法得到可用的许可数目。
acquire()获取一个许可,和release()释放一个许可,代码实例:
package com.javaedge.concurrency.example.aqs;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
@Slf4j
public class SemaphoreExample1 {
private final static int threadCount = 20;
public static void main(String[] args) throws Exception {
ExecutorService exec = Executors.newCachedThreadPool();
final Semaphore semaphore = new Semaphore(3);
for (int i = 0; i < threadCount; i++) {
final int threadNum = i;
exec.execute(() -> {
try {
semaphore.acquire(); // 获取一个许可
test(threadNum);
semaphore.release(); // 释放一个许可
log.info("{}", threadNum+"《释放许可");
} catch (Exception e) {
log.error("exception", e);
}
});
}
exec.shutdown();
}
private static void test(int threadNum) throws Exception {
log.info("{}", threadNum+"》获取许可");
Thread.sleep(1000);
}
}
执行结果
16:00:29.474 [pool-1-thread-2] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample1 - 1》获取许可
16:00:29.474 [pool-1-thread-3] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample1 - 2》获取许可
16:00:29.474 [pool-1-thread-1] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample1 - 0》获取许可
16:00:30.478 [pool-1-thread-3] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample1 - 2《释放许可
16:00:30.478 [pool-1-thread-1] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample1 - 0《释放许可
16:00:30.478 [pool-1-thread-4] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample1 - 3》获取许可
16:00:30.478 [pool-1-thread-2] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample1 - 1《释放许可
16:00:30.478 [pool-1-thread-5] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample1 - 4》获取许可
16:00:30.478 [pool-1-thread-6] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample1 - 5》获取许可
16:00:31.479 [pool-1-thread-5] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample1 - 4《释放许可
16:00:31.479 [pool-1-thread-7] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample1 - 6》获取许可
16:00:31.479 [pool-1-thread-8] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample1 - 7》获取许可
16:00:31.479 [pool-1-thread-9] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample1 - 8》获取许可
16:00:31.479 [pool-1-thread-4] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample1 - 3《释放许可
16:00:31.479 [pool-1-thread-6] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample1 - 5《释放许可
16:00:32.479 [pool-1-thread-8] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample1 - 7《释放许可
16:00:32.479 [pool-1-thread-9] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample1 - 8《释放许可
16:00:32.479 [pool-1-thread-7] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample1 - 6《释放许可
16:00:32.479 [pool-1-thread-10] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample1 - 9》获取许可
16:00:32.479 [pool-1-thread-11] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample1 - 10》获取许可
16:00:32.479 [pool-1-thread-12] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample1 - 11》获取许可
16:00:33.479 [pool-1-thread-10] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample1 - 9《释放许可
16:00:33.479 [pool-1-thread-12] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample1 - 11《释放许可
16:00:33.479 [pool-1-thread-13] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample1 - 12》获取许可
16:00:33.479 [pool-1-thread-14] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample1 - 13》获取许可
16:00:33.479 [pool-1-thread-11] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample1 - 10《释放许可
16:00:33.479 [pool-1-thread-15] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample1 - 14》获取许可
16:00:34.479 [pool-1-thread-15] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample1 - 14《释放许可
16:00:34.479 [pool-1-thread-16] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample1 - 15》获取许可
16:00:34.479 [pool-1-thread-17] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample1 - 16》获取许可
16:00:34.479 [pool-1-thread-18] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample1 - 17》获取许可
16:00:34.479 [pool-1-thread-13] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample1 - 12《释放许可
16:00:34.479 [pool-1-thread-14] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample1 - 13《释放许可
16:00:35.479 [pool-1-thread-16] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample1 - 15《释放许可
16:00:35.479 [pool-1-thread-20] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample1 - 19》获取许可
16:00:35.479 [pool-1-thread-19] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample1 - 18》获取许可
16:00:35.479 [pool-1-thread-18] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample1 - 17《释放许可
16:00:35.479 [pool-1-thread-17] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample1 - 16《释放许可
16:00:36.479 [pool-1-thread-19] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample1 - 18《释放许可
16:00:36.479 [pool-1-thread-20] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample1 - 19《释放许可
同时只能有3个获取许可
acquire(permits)获取permits个许可,和release(permits)释放permits个许可,代码实例:
package com.javaedge.concurrency.example.aqs;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
@Slf4j
public class SemaphoreExample2 {
private final static int threadCount = 20;
public static void main(String[] args) throws Exception {
ExecutorService exec = Executors.newCachedThreadPool();
final Semaphore semaphore = new Semaphore(3);
for (int i = 0; i < threadCount; i++) {
final int threadNum = i;
exec.execute(() -> {
try {
semaphore.acquire(3); // 获取多个许可
test(threadNum);
semaphore.release(3); // 释放多个许可
log.info("{}", threadNum+"》释放许可");
} catch (Exception e) {
log.error("exception", e);
}
});
}
exec.shutdown();
}
private static void test(int threadNum) throws Exception {
log.info("{}", threadNum+"》获取许可");
Thread.sleep(1000);
}
}
执行结果
16:01:43.299 [pool-1-thread-1] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample2 - 0》获取许可
16:01:44.303 [pool-1-thread-1] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample2 - 0》释放许可
16:01:44.303 [pool-1-thread-2] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample2 - 1》获取许可
16:01:45.303 [pool-1-thread-2] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample2 - 1》释放许可
16:01:45.303 [pool-1-thread-3] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample2 - 2》获取许可
16:01:46.303 [pool-1-thread-4] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample2 - 3》获取许可
16:01:46.303 [pool-1-thread-3] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample2 - 2》释放许可
16:01:47.303 [pool-1-thread-4] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample2 - 3》释放许可
16:01:47.303 [pool-1-thread-5] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample2 - 4》获取许可
16:01:48.303 [pool-1-thread-5] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample2 - 4》释放许可
16:01:48.303 [pool-1-thread-6] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample2 - 5》获取许可
16:01:49.303 [pool-1-thread-6] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample2 - 5》释放许可
16:01:49.303 [pool-1-thread-7] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample2 - 6》获取许可
16:01:50.303 [pool-1-thread-7] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample2 - 6》释放许可
16:01:50.303 [pool-1-thread-8] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample2 - 7》获取许可
16:01:51.303 [pool-1-thread-8] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample2 - 7》释放许可
16:01:51.303 [pool-1-thread-9] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample2 - 8》获取许可
16:01:52.303 [pool-1-thread-9] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample2 - 8》释放许可
16:01:52.303 [pool-1-thread-10] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample2 - 9》获取许可
16:01:53.303 [pool-1-thread-10] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample2 - 9》释放许可
16:01:53.303 [pool-1-thread-11] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample2 - 10》获取许可
16:01:54.303 [pool-1-thread-11] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample2 - 10》释放许可
16:01:54.303 [pool-1-thread-12] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample2 - 11》获取许可
16:01:55.303 [pool-1-thread-12] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample2 - 11》释放许可
16:01:55.303 [pool-1-thread-13] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample2 - 12》获取许可
16:01:56.303 [pool-1-thread-13] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample2 - 12》释放许可
16:01:56.303 [pool-1-thread-14] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample2 - 13》获取许可
16:01:57.303 [pool-1-thread-14] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample2 - 13》释放许可
16:01:57.303 [pool-1-thread-15] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample2 - 14》获取许可
16:01:58.304 [pool-1-thread-15] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample2 - 14》释放许可
16:01:58.304 [pool-1-thread-16] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample2 - 15》获取许可
16:01:59.304 [pool-1-thread-16] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample2 - 15》释放许可
16:01:59.304 [pool-1-thread-17] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample2 - 16》获取许可
16:02:00.304 [pool-1-thread-17] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample2 - 16》释放许可
16:02:00.304 [pool-1-thread-18] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample2 - 17》获取许可
16:02:01.304 [pool-1-thread-18] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample2 - 17》释放许可
16:02:01.304 [pool-1-thread-19] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample2 - 18》获取许可
16:02:02.304 [pool-1-thread-19] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample2 - 18》释放许可
16:02:02.304 [pool-1-thread-20] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample2 - 19》获取许可
16:02:03.304 [pool-1-thread-20] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample2 - 19》释放许可
Process finished with exit code 0
tryAcquire()尝试获取一个许可代码实例:
package com.javaedge.concurrency.example.aqs;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
@Slf4j
public class SemaphoreExample4 {
private final static int threadCount = 20;
public static void main(String[] args) throws Exception {
ExecutorService exec = Executors.newCachedThreadPool();
final Semaphore semaphore = new Semaphore(3);
for (int i = 0; i < threadCount; i++) {
final int threadNum = i;
exec.execute(() -> {
try {
if (semaphore.tryAcquire()) { // 尝试获取一个许可
test(threadNum);
semaphore.release(); // 释放一个许可
log.info("{}",threadNum + "释放许可");
}
} catch (Exception e) {
log.error("exception", e);
}
});
}
exec.shutdown();
}
private static void test(int threadNum) throws Exception {
log.info("{}", threadNum+"获取许可");
Thread.sleep(1000);
}
}
执行结果:
16:08:27.863 [pool-1-thread-4] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample3 - 3>获取许可
16:08:27.863 [pool-1-thread-1] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample3 - 0>获取许可
16:08:27.863 [pool-1-thread-2] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample3 - 1>获取许可
16:08:28.867 [pool-1-thread-4] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample3 - 3>释放许可
16:08:28.867 [pool-1-thread-2] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample3 - 1>释放许可
16:08:28.867 [pool-1-thread-1] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample3 - 0>释放许可
Process finished with exit code 0
同一时间只有三个线程获取许可成功,其他获取许可失败返回false而不执行
tryAcquire(5000, TimeUnit.MILLISECONDS)在指定时间尝试获取一个许可代码实例:
package com.javaedge.concurrency.example.aqs;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
@Slf4j
public class SemaphoreExample4 {
private final static int threadCount = 20;
public static void main(String[] args) throws Exception {
ExecutorService exec = Executors.newCachedThreadPool();
final Semaphore semaphore = new Semaphore(3);
for (int i = 0; i < threadCount; i++) {
final int threadNum = i;
exec.execute(() -> {
try {
if (semaphore.tryAcquire(5000, TimeUnit.MILLISECONDS)) { // 尝试获取一个许可
test(threadNum);
semaphore.release(); // 释放一个许可
log.info("{}",threadNum + "释放许可");
}
} catch (Exception e) {
log.error("exception", e);
}
});
}
exec.shutdown();
}
private static void test(int threadNum) throws Exception {
log.info("{}", threadNum+"获取许可");
Thread.sleep(1000);
}
}
执行结果:
16:10:09.478 [pool-1-thread-1] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample4 - 0获取许可
16:10:09.478 [pool-1-thread-2] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample4 - 1获取许可
16:10:09.478 [pool-1-thread-3] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample4 - 2获取许可
16:10:10.482 [pool-1-thread-3] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample4 - 2释放许可
16:10:10.482 [pool-1-thread-4] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample4 - 3获取许可
16:10:10.482 [pool-1-thread-1] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample4 - 0释放许可
16:10:10.482 [pool-1-thread-5] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample4 - 4获取许可
16:10:10.482 [pool-1-thread-6] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample4 - 5获取许可
16:10:10.482 [pool-1-thread-2] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample4 - 1释放许可
16:10:11.482 [pool-1-thread-6] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample4 - 5释放许可
16:10:11.482 [pool-1-thread-7] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample4 - 6获取许可
16:10:11.482 [pool-1-thread-8] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample4 - 7获取许可
16:10:11.482 [pool-1-thread-9] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample4 - 8获取许可
16:10:11.482 [pool-1-thread-5] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample4 - 4释放许可
16:10:11.482 [pool-1-thread-4] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample4 - 3释放许可
16:10:12.482 [pool-1-thread-8] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample4 - 7释放许可
16:10:12.482 [pool-1-thread-10] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample4 - 9获取许可
16:10:12.482 [pool-1-thread-9] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample4 - 8释放许可
16:10:12.482 [pool-1-thread-11] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample4 - 10获取许可
16:10:12.482 [pool-1-thread-12] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample4 - 11获取许可
16:10:12.482 [pool-1-thread-7] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample4 - 6释放许可
16:10:13.482 [pool-1-thread-12] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample4 - 11释放许可
16:10:13.482 [pool-1-thread-14] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample4 - 13获取许可
16:10:13.482 [pool-1-thread-15] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample4 - 14获取许可
16:10:13.482 [pool-1-thread-10] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample4 - 9释放许可
16:10:13.482 [pool-1-thread-11] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample4 - 10释放许可
16:10:13.482 [pool-1-thread-13] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample4 - 12获取许可
16:10:14.482 [pool-1-thread-13] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample4 - 12释放许可
16:10:14.482 [pool-1-thread-15] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample4 - 14释放许可
16:10:14.482 [pool-1-thread-14] INFO com.javaedge.concurrency.example.aqs.SemaphoreExample4 - 13释放许可
Process finished with exit code 0
在指定时间只有15个线程在指定时间尝试获取许可成功
下面对上面说的三个辅助类进行一个总结:
1)CountDownLatch和CyclicBarrier都能够实现线程之间的等待,只不过它们侧重点不同:
CountDownLatch一般用于某个线程A等待若干个其他线程执行完任务之后,它才执行;
而CyclicBarrier一般用于一组线程互相等待至某个状态,然后这一组线程再同时执行;
另外,CountDownLatch是不能够重用的,而CyclicBarrier是可以重用的。
2)Semaphore其实和锁有点类似,它一般用于控制对某组资源的访问权限。