java.util.concurrent 中的构件
CountDownLatch
CountDownLatch
被用于同步一个或多个任务,强制它们等待一组任务的操作。
public class Main {
static final int SIZE = 10;
public static void main(String[] args) throws InterruptedException, IOException {
ExecutorService exec = Executors.newCachedThreadPool();
CountDownLatch latch = new CountDownLatch(SIZE);
int count = 10;
while (count-- > 0) {
exec.execute(() -> {
try {
TimeUnit.MILLISECONDS.sleep(100);
System.out.println("one task was finished");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
latch.countDown();
}
});
}
exec.execute(() -> {
try {
latch.await();
System.out.println("submit tasks report");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
TimeUnit.MILLISECONDS.sleep(4000);
exec.shutdownNow();
}
}
one task was finished
one task was finished
one task was finished
one task was finished
one task was finished
one task was finished
one task was finished
one task was finished
one task was finished
one task was finished
submit tasks report
任何在 CountDownLatch
对象上调用 await()
方法的任务都将阻塞,直到这个 latch 计数为 0。
CountDownLatch
被设计为只能使用一次,不能重置计数器的值。
CyclicBarrier
可以多次重用的 CountDownLatch
。
public class Main {
private static final int SIZE = 10;
private static Random random = new Random(47);
public static void main(String[] args) throws InterruptedException, IOException {
ExecutorService exec = Executors.newCachedThreadPool();
CyclicBarrier barrier = new CyclicBarrier(SIZE, () -> System.out.println("submit tasks report"));
int count = 10;
while (count-- > 0){
exec.execute(() -> {
try {
TimeUnit.MILLISECONDS.sleep(random.nextInt(1000));
System.out.println("one task was finished");
barrier.await();
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
});
}
TimeUnit.MILLISECONDS.sleep(4000);
exec.shutdownNow();
}
}
当 CyclicBarrier
对象所调用的 await()
次数,即等待这个资源而阻塞的线程数,达到这个构造器中设置的值时,将执行构造器中传入的Runnable()
方法,当我把 count 值改为 20 的时候,可以看到这个 "submit tasks report" 输出了 2 次,即达到我们要的效果。
ScheduledExecutor
使用 schedule()
(运行一次任务) 或 scheduleAtFixedRate()
(每隔规则的时间重复执行任务)。
public class Main {
private static final int SIZE = 5;
private static Random random = new Random(47);
public static void main(String[] args) throws InterruptedException, IOException {
long start = System.currentTimeMillis();
ScheduledExecutorService service = Executors.newScheduledThreadPool(SIZE);
for (int i = 0; i < SIZE; i++) {
service.schedule(() -> System.out.println(System.currentTimeMillis() - start),
random.nextInt(3000), TimeUnit.MILLISECONDS);
}
TimeUnit.SECONDS.sleep(5);
service.shutdownNow();
}
}
使用 ScheduledExecutor
区别于 Timer
的是,Timer
不会创建新的线程去执行这个任务,先前的任务的执行时间大于与下一个任务的间隔,会导致下一个任务推迟。