并发工具类介绍
常用并发工具类有以下几种:
- Fork/Join
- CountDownLatch
- CyclicBarrier
- Semaphore
- Exchanger
- Callable、Future、FutureTask
Fork/Join
Fork/Join框架是分而治之思想的一种体现,它通过两个类来实现这个功能。
- RecursiveAction:用于没有返回值的情况
- RecursiveTask:用于有返回值的情况
使用这个框架的流程如下:
- 新建一个Fork/Join池(new ForkJoinPool())
- 新建一个实现RecursiveAction或RecursiveTask的类,并实现它的compute方法,再创建这个类的对象
- 调用Pool的invoke方法,引入2中的对象作为参数
- 调用2对象的join()方法
CountDownLatch
CountDownLatch为闭锁,主要用于控制线程执行的顺序。用法如下:
- 创建一个CountDownLatch对象
- 初始化该对象,new CountDownLatch(int n),这个n可以理解为一共设置了n个锁
- 在执行方法中调用锁对象的CountDown()方法,可以理解为解开一个锁
- 使用锁对象的await()方法,这时如果锁全部被解开(n为0),则可以越过await()方法往下执行,若仍然有锁(n>0),则程序会停止在await()处,不再往下运行
闭锁机制可以理解为一个加强的join()方法,由于其可以控制执行顺序,也就不难想到它可以控制多线程同时运行(即运用CountDown方法统一解开锁),也可以避免死锁。
CyclicBarrier
CyclicBarrier是一个同步屏障,用于控制多个线程到达同一个程度后开始同时运行。用法如下:
- 创建一个CyclicBarrier对象
- 初始化该对象,参数为一个整型和一个实现了Runnable的类对象,整型代表有几个需要同步的线程,类对象代表过了屏障之后需要执行的线程,可缺省。
- 在线程中需要停止并等待其他线程进行的地方使用CyclicBarrier对象的await()方法
CountDownLatch和CyclicBarrier的区别
- 前者的等待是外部因素决定的,只有当锁都被打开之后才能继续执行,而后者的等待是由内部自己决定的,只有所有线程都运行到某一位置时才会继续运行
- 前者可以设定大于线程数量的CountDownLatch,而CyclicBarrier却必须和线程数目一样
Semaphore
Semaphore是信号量的意思,可以理解为一个线程访问公共资源的许可证,使用如下:
- 初始化Semaphore,传入一个参数代表公共资源的个数和一个表示是否为先进先出的布尔值
- 每次使用公共资源,则调用该对象的acquire方法
- 每次释放公共资源,则调用该对象的release方法
- 通常与Lock一起使用
Exchanger
用于两个线程之间互相交换信息,用法如下
- 创建Exchanger对象并制定类型
- 分别在两个线程中调用该对象的exchange方法,传入参数为该线程发出去的实体
也就是说,exchange方法表示把参数传递出去并接受另一个exchange传递过来的参数。
值得注意的是,当一个线程调用exchange时,若未收到另外线程传入的exchange值,那么这个线程是阻塞的,直至对方线程的exchange传来值才会继续往下运行。
Callable、Future、FutureTask
Callable是JDK1.5之后的新功能,用于创建线程。与传统的集成Thread类和实现Runnable接口相比,Callable的优势在于它创建的线程可以有返回值。
- Callable和Runable比较想象,他们都是接口,不能的是Callable可以传递一个泛型,并且需要实现的方法变成了call而非run,这个call方法的返回值则是Callable传递的泛型类型
- Future接口包含几个方法:
- isDone: 若结束返回true
- isCancelled: 任务完成前被取消,返回true;
- cancel(boolean):
1、 取消任务成功,返回true,取消任务失败则返回false
2、 参数mayInterruptIfRunning表示是否允许取消正在执行却没有执行完毕的任务,如果设置true,则表示可以取消正在执行过程中的任务。
3、 如果任务已经完成,返回false。任务还未执行,返回true。
FutureTask
- 实现了RunnableFuture接口,而RunnableFuture接口继承了Runnable接口和Future接口,所以具有双重功能。
- FutureTask是Future接口的一个唯一实现类