Java并发编程的艺术:(8) Java 中的并发工具类
文章目录
等待多线程完成的 CountDownLatch
CountDownLatch 允许一个或多个线程等待其他线程完成操作。
比如这样一个需求:我们需要解析一个 Excel 里多个 sheet 的数据,此时可以考虑使用多线程,每个线程解析一个sheet里的数据,等到所有的 sheet 都解析完之后,程序需要提示解析完成。在这个需求中,要实现主线程等待所有线程完成 sheet 的解析操作,最简单的做法是使用 join() 方法。
在 JDK 1.5 之后的并发包中提供的 CountDownLatch 也可以实现 join 的功能,并且比 join 的功能更多,如下所示:
public class CountDownLatchTest {
static CountDownLatch c = new CountDownLatch(2);
public static void main(String[] args) throws InterruptedException {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(1);
c.countDown();
System.out.println(2);
c.countDown();
}
}).start();
c.await();
System.out.println("3");
}
}
CountDownLatch 的构造函数接收一个 int 类型的参数作为计数器,如果需要等待 N 个点完成,这里就传入 N。
当我们调用 CountDownLatch 的 countDown 方法时, N 就会减 1,CountDownLacht 的 await 方法就会阻塞当前线程,直到 N 变成零。由于 countDown 方法可以用在任何地方,所以说这里的 N 个点,可以是 N 个线程,也可以是 1 个线程里的 N 个执行步骤。用在多线程时,只需要把这个 CountDownLatch 的引用传递到线程里即可。
同步屏障 CyclicBarrier
CyclicBarrier 的字面意思是可循环使用(Cyclic)的屏障(Barrier)。它要做的事情是,让一组线程到达一个屏障(也可以叫做同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续运行。
CyclicBarrier 简介
CyclicBarrier 默认的狗仔方法是 CyclicBarrier(int parties), 其参数表示屏障拦截数量,每个线程调用 await 方法告诉 CyclicBarrier 我已经到达了 屏障,然后当前线程被阻塞。
CyclicBarrier 的应用场景
CyclicBarrier 可以用于多线程计算数据,最后合并计算结果的场景。例如,用一个 Excel 保存了用户所有的银行流水,每个 Sheet 保存一个账户近一年的每笔银行流水,现在需要统计用户的日均银行流水,先用多线程处理每个 sheet 里的银行流水,都执行完之后,得到每个 sheet 的日均银行流水,最后,再用 barrierAction 用这些线程的计算结果,计算出整个 Excel 的日均银行流水。
CyclicBarrier 和 CountDownLatch 的区别
CountDownLatch 的计数器只能使用一次,而CyclicBarrier 的计数器可以使用 reset() 方法重置。所以 CyclicBarrier 能处理更为复杂的业务场景。例如,如果计算发生错误,可以重置计算器,并让线程重新执行一次。
控制并发线程数的 Semaphore
Semaphore 可以用作流量控制,特别是公用资源有限的应用场景,比如数据库连接。比如有这样一个需求:要读取几万个文件的数据,因为都是 IO 密集型任务,我们可以启动几十个线程并发地读取,但是如果读到内存以后,还需要存储到数据库中,而数据库的连接只有 10 个,这时我们必须控制只有 10 个线程同时获取数据库连接保存数据,否则会报错无法获取数据库连接。这个时候,就可以使用 Semaphore 来做流量控制。
线程间交换数据的 Exchanger
Exchanger 是一个用于线程间协作的工具类。Exchange 用于进行线程间的数据交换。它提供一个同步点,在这个同步点,两个线程可以交换彼此的数据。这两个线程通过 exchange 方法交换数据,如果第一个线程先执行 exchange() 方法,它会一直等待第二个线程也执行 exchange 方法,当两个线程都到达同步点时,这两个线程就可以交换数据,将本线程生产出来的数据传递给对方。
参考
《Java 并发编程的艺术》
推荐阅读
-
Java日期时间API系列8-----Jdk8中java.time包中的新的日期时间API类的LocalDate源码分析
-
Java日期时间API系列11-----Jdk8中java.time包中的新的日期时间API类,使用java8日期时间API重写农历LunarDate
-
Java日期时间API系列9-----Jdk8中java.time包中的新的日期时间API类的Period和Duration的区别
-
【并发编程】Java对并发编程的支持历史
-
荐 Java——数据库编程JDBC之数据库连接池技术(C3P0与Druid,提供了Druid的工具类)
-
Java并发编程之常用的辅助类详解
-
Java并发编程中的若干核心技术,向高手进阶!
-
深入讲解Java编程中类的生命周期
-
Java并发工具类CountDownLatch源码中的例子
-
java中金额元转万元工具类的实例