1. Callable
使用方法:
public class CallableDemo {
public static void main(String[] args) {
CallableTest callableTest = new CallableTest();
FutureTask<Integer> futureTask = new FutureTask(callableTest);
new Thread(futureTask,"t1").start();
try {
System.out.println(futureTask.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
class CallableTest implements Callable<Integer>{
@Override
public Integer call() throws Exception {
Integer num = 0;
for (int i = 0; i < 10; i++) {
num++;
}
return num;
}
}
优点:
- 可以获取通过get方法获取线程的返回值,注意get方法阻塞线程。
- 支持异常捕获
- 支持泛型
2. CountDownLatch
CountDownLatch(倒计时计算器)使用说明
方法说明
public void countDown()
递减锁存器的计数,如果计数到达零,则释放所有等待的线程。如果当前计数大于零,则将计数减少.
public boolean await(long timeout,TimeUnit unit) throws InterruptedException
使当前线程在锁存器倒计数至零之前一直等待,除非线程被中断或超出了指定的等待时间。如果当前计数为零,则此方法立刻返回true值。
如果当前计数大于零,则出于线程调度目的,将禁用当前线程,且在发生以下三种情况之一前,该线程将一直出于休眠状态:
由于调用countDown()方法,计数到达零;或者其他某个线程中断当前线程;或者已超出指定的等待时间。
- 如果计数到达零,则该方法返回true值。
- 如果当前线程,在进入此方法时已经设置了该线程的中断状态;或者在等待时被中断,则抛出InterruptedException,并且清除当前线程的已中断状态。
- 如果超出了指定的等待时间,则返回值为false。如果该时间小于等于零,则该方法根本不会等待。
参数:
timeout-要等待的最长时间
unit-timeout 参数的时间单位
返回:
如果计数到达零,则返回true;如果在计数到达零之前超过了等待时间,则返回false
抛出:
InterruptedException-如果当前线程在等待时被中断
例子:线程a需要等待线程b和c完成在执行
public class CountDownLatchDemo {
public static void main(String[] args) {
CDLDPrint cdldPrint = new CDLDPrint();
final CountDownLatch latch = new CountDownLatch(2); //需要等待b,c线程完成,所以为2
new Thread(()->{
try {
latch.await(); //等待bc线程执行完成
} catch (InterruptedException e) {
e.printStackTrace();
}
cdldPrint.printA();
},"线程A").start();
new Thread(()->{
cdldPrint.printB();
latch.countDown(); //计数器减一
},"线程B").start();
new Thread(()->{
cdldPrint.printC();
latch.countDown(); //计数器减一
},"线程C").start();
}
}
class CDLDPrint{
public void printA(){
System.out.println(Thread.currentThread().getName()+"aaaaaaaaaaaaaaaaa");
}
public void printB(){
System.out.println(Thread.currentThread().getName()+"bbbbbbbbbbbbbbbb");
}
public void printC(){
System.out.println(Thread.currentThread().getName()+"ccccccccccccccccc");
}
}
3. CyclicBarrier
就像生活中我们会约朋友们到某个餐厅一起吃饭,有些朋友可能会早到,有些朋友可能会晚到,但是这个餐厅规定必须等到所有人到齐之后才会让我们进去。这里的朋友们就是各个线程,餐厅就是 CyclicBarrier。类似于累加器,线程运行达到多少时,开始执行。
public int await() throws InterruptedException, BrokenBarrierException
等待所有parties已经在这个障碍上调用了await
。
如果当前线程不是最后一个线程,那么它被禁用以进行线程调度,并且处于休眠状态,直到发生下列事情之一:
- 最后一个线程到达; 要么
- 一些其他线程当前线程为interrupts ; 要么
- 一些其他线程interrupts其他等待线程之一; 要么
- 一些其他线程在等待屏障时超时; 要么
- 其他一些线程在这个屏障上调用
reset()
。
如果当前线程:
- 在进入该方法时设置了中断状态; 要么
- 是等待interrupted
然后InterruptedException
被关上,当前线程的中断状态被清除。
如果屏蔽是reset()
,而任何线程正在等待,或者当await
被调用时屏障is broken ,或者任何线程等待,则抛出BrokenBarrierException
。
如果任何线程在等待的时候是interrupted ,那么所有其他等待的线程将会丢失BrokenBarrierException
,并且屏障被置于断开的状态。
如果当前线程是要到达的最后一个线程,并且在构造函数中提供非空障碍操作,则当前线程在允许其他线程继续之前运行该动作。 如果在屏障动作期间发生异常,则该异常将在当前线程中传播,并且屏障置于断开状态。
结果
当前线程的到达索引,其中索引 getParties() - 1
表示第一个到达,零表示最后到达
异常
InterruptedException
- 如果当前线程在等待时中断
BrokenBarrierException
- 如果当前线程正在等待,或者屏蔽被重置,或者当 await
时屏障被破坏,或者屏蔽动作(如果存在)由于异常而失败,则 另一个线程被中断或超时
例子:实现abc三个线程同时执行。
public class CyclicBarrierDemo {
public static void main(String[] args) {
CBDPrint cbdPrint = new CBDPrint();
final CyclicBarrier cyclicBarrier = new CyclicBarrier(3);
new Thread(()->{
try {
cyclicBarrier.await();
cbdPrint.printA();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
},"线程A").start();
new Thread(()->{
try {
cyclicBarrier.await();
cbdPrint.printB();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
},"线程B").start();
new Thread(()->{
try {
cyclicBarrier.await();
cbdPrint.printB();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
},"线程C").start();
}
}
class CBDPrint{
public void printA(){
System.out.println(Thread.currentThread().getName()+"aaaaaaaaaaaaaaaaa");
}
public void printB(){
System.out.println(Thread.currentThread().getName()+"bbbbbbbbbbbbbbbb");
}
public void printC(){
System.out.println(Thread.currentThread().getName()+"ccccccccccccccccc");
}
}