java.util.concurrent工具包(一)
1. CountDownLatch
----作用----
-
countDownLatch这个类使一个线程等待其他线程各自执行完毕后再执行。
-
是通过一个计数器来实现的,计数器的初始值是线程的数量。每当一个线程执行完毕后,计数器的值就-1,当计数器的值为0时,表示所有线程都执行完毕,然后在闭锁上等待的线程就可以恢复工作了。
----构造函数----
构造函数 | 作用 | 备注 |
---|---|---|
public CountDownLatch(int count) | 初始化this.count = count的CountDownLatch | 如果count<0 会抛出IllegalArgumentException |
----常用API----
API | 作用 | 备注 |
---|---|---|
void await() throws InterruptedException | 调用await()方法的线程会被挂起,它会等待直到count值为0才继续执行 | 阻塞方法,一直到count为0才退出 |
boolean await(long timeout, TimeUnit unit) throws InterruptedException | 和await()类似,只不过等待一定的时间后count值还没变为0的话就会继续执行 | 返回值(是否提前完成>>正常出口 true) 超时出去的 false |
void countDown() | 将count自减 | 如果count已经是0了依然能够调用,但是不会下减也不会报错 |
long getCount() | 获得当前count |
----使用案例----
package myConcurrent.s2020_03_25;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;
public class CountDownLatchExample {
public static void main(String[] args) throws InterruptedException {
int n = 4;
final CountDownLatch countDownLatchLock = new CountDownLatch(n);
IntStream.range(0, n).forEach(i -> {
new Thread(() -> {
System.out.println(Thread.currentThread() + " Working~2S!");
try {
TimeUnit.SECONDS.sleep(20);
countDownLatchLock.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "Thread-" + i).start();
});
boolean flag = countDownLatchLock.await(2,TimeUnit.SECONDS);
System.out.println("是否正常完成?" + flag);
System.out.println("等待的数量 : " + countDownLatchLock.getCount());
countDownLatchLock.await();
System.out.println("这次是真的完成了!");
//尝试在下减一次
countDownLatchLock.countDown();
System.out.println("最后的需要等待的count " + countDownLatchLock.getCount());
}
}
----输出----
Thread[Thread-0,5,main] Working~2S!
Thread[Thread-1,5,main] Working~2S!
Thread[Thread-2,5,main] Working~2S!
Thread[Thread-3,5,main] Working~2S!
是否正常完成?false
等待的数量 : 4
这次是真的完成了!
最后的需要等待的count 0
2. CyclicBarrier
----作用----
CyclicBarrier是一个同步辅助类,允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point)。因为该 barrier 在释放等待线程后可以重用,所以称它为循环 的 barrier。
----构造函数----
构造函数 | 作用 | 备注 |
---|---|---|
public CyclicBarrier(int parties, Runnable barrierAction) | 设置互相等待的线程数到达parties之后,会触发的一个线程 barrierAction | 如果parties<0 会抛出一个异常 |
public CyclicBarrier(int parties) | 会调用this(parties,null) |
----常用API----
API | 作用 | 备注 |
---|---|---|
int getParties() | 获得CyclicBarrier打开屏障需要的数量 | |
int getNumberWaiting() | 获得正在等待的线程数 | |
int await() | 在CyclicBarrier上等待的线程数量达到parties,则所有线程被释放,继续执行。 当前线程被中断,则抛出InterruptedException异常,并停止等待,继续执行。 其他等待的线程被中断,则当前线程抛出BrokenBarrierException异常,并停止等待,继续执行。 其他等待的线程超时,则当前线程抛出BrokenBarrierException异常,并停止等待,继续执行。 其他线程调用CyclicBarrier.reset()方法,则当前线程抛出BrokenBarrierException异常,并停止等待,继续执行。 | 返回值是当前的线程第一个到达屏障的 |
int await(timeout,TimeUnit) | 几乎与await()相同,但是如果超时的话,会抛出TimeoutException | 同await() |
boolean isBroken() | 如果屏障已经被打破 则返回true | 如果被调用了reset,该屏障会被修复 |
void reset() | 修复屏障, 重复使用 |
----使用案例----
-
Example1
package myConcurrent.s2020_03_25; import java.util.concurrent.BrokenBarrierException; import java.util.concurrent.CyclicBarrier; import java.util.concurrent.TimeUnit; import java.util.stream.IntStream; /** * 测试只有 阈值的 屏障构造 * */ public class CyclicBarrierExample1 { public static void main(String[] args) throws BrokenBarrierException, InterruptedException { int n = 10; final CyclicBarrier cyclicBarrier = new CyclicBarrier(n + 1); IntStream.range(0, n).forEach(i -> { new Thread(() -> { try { TimeUnit.SECONDS.sleep(2); int index = cyclicBarrier.await(); System.out.println(Thread.currentThread().getName() + " 是第 " + index + " 到达屏障的!"); } catch (InterruptedException e) { System.out.println("线程被打断"); e.printStackTrace(); } catch (BrokenBarrierException e) { System.out.println("屏障被重置"); e.printStackTrace(); } }, "Thread-" + i) { }.start(); }); int mainIndex = cyclicBarrier.await(); System.out.println("主线程是第 " + mainIndex + " 个到达屏障"); System.out.println("屏障是否被打破了:" + cyclicBarrier.isBroken()); } }
-
Example2
package myConcurrent.s2020_03_25; import java.util.concurrent.BrokenBarrierException; import java.util.concurrent.CyclicBarrier; import java.util.concurrent.TimeUnit; import java.util.stream.IntStream; /** * 测试带回调的构造屏障 * **/ public class CyclicBarrierExample2 { public static void main(String[] args) { int n = 10; final CyclicBarrier cyclicBarrier = new CyclicBarrier(n, () -> { System.out.println("屏障已经被打破!"); }); IntStream.range(0, n).forEach(i -> { new Thread(() -> { try { TimeUnit.SECONDS.sleep(1); cyclicBarrier.await(); } catch (InterruptedException | BrokenBarrierException e) { e.printStackTrace(); } }).start(); }); } }
-
Example3
package myConcurrent.s2020_03_25; import java.util.concurrent.BrokenBarrierException; import java.util.concurrent.CyclicBarrier; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.stream.IntStream; /** * 测试带有时间的await方法 * 以及 reset 方法 */ public class CyclicBarrierExample3 { public static void main(String[] args) throws InterruptedException{ int n = 10; final CyclicBarrier cyclicBarrier = new CyclicBarrier(n, () -> { System.out.println("屏障已经被打破"); }); System.out.println("等待中的线程数量:" + cyclicBarrier.getNumberWaiting()); System.out.println("屏障打破需要的等待线程数量:" + cyclicBarrier.getParties()); System.out.println("屏障是否被破坏" + cyclicBarrier.isBroken()); IntStream.range(0, n-1).forEach(i -> { new Thread(() -> { try { cyclicBarrier.await(3L, TimeUnit.SECONDS); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { System.out.println("由于一个线程的超时错误! 导致屏障已经毁坏!"); // e.printStackTrace(); } catch (TimeoutException e) { System.out.println(Thread.currentThread().getName() + " 等待已经超时了-----"); // e.printStackTrace(); } },"Thread-" + i).start(); }); TimeUnit.SECONDS.sleep(4); System.out.println(">>> 屏障是否坏了 : " + cyclicBarrier.isBroken()); try { cyclicBarrier.await(); } catch (BrokenBarrierException e) { System.out.println("屏障已经坏了!"); } //恢复 屏障 cyclicBarrier.reset(); System.out.println("等待中的线程数量:" + cyclicBarrier.getNumberWaiting()); System.out.println("屏障打破需要的等待线程数量:" + cyclicBarrier.getParties()); System.out.println("屏障是否被破坏" + cyclicBarrier.isBroken()); } }
3. CountDownLatch 和 CyclicBarrier 的区别
- countDownLatch是一个计数器,线程完成一个记录一个,计数器递减,只能只用一次
- CyclicBarrier的计数器更像一个阀门,需要所有线程都到达,然后继续执行,计数器递增,提供reset功能,可以多次使用
- CyClicBarrier 是需要 线程相互协作的,而CountDownLatch 不需要线程相互协作,只要不断的 countDown()
4. Phaser ( JDK1.7 )
-----杂项-----
- 同时拥有着 CountDownLatch 和 CyclicBarrier 的特性
- 能够形成父子结构的关系
- 一旦形成父子结构 , 一个相位器的关闭,会导致所有相位器的关闭
- 一个相位器被注册为父相位器,如果子相位器的parties不为0,那么 父相位器 的parties 会+1
- 子相位器相位改变一次之后,就不能够再arrive,否则会抛出异常, 同时 父相位的到达数会+1
-----构造函数-----
构造函数 | 作用 | 备注 |
---|---|---|
Phaser() | 构造一个没有父Phaser和0个证书的phaser | |
Phaser(int parties) | 创建一个parties个证书的phaser | <0 或者 大于 1<<16 都会报错 |
Phaser(Phaser parent) | 创建一个带有父的phaser | |
Phaser(Phaser parent, int parties) | 主要的实例方法 |
-----常用API-----
API | 作用 | 备注 |
---|---|---|
int arrive() | 表示该线程已经到达了目标, 相位器 旋转了1 , 返回值是 当前的相位,如果该相位器已经终结,那么返回值就是一个负数的 | 不会发生阻塞 |
int arriveAndAwaitAdvance() | 到达并且等待其他线程,到达屏障的阀值,就能打破内存屏障,返回值 是下一个相位 ( 但是不是精确值 ,受到多线程的 影响),如果 该相位器关闭,则返回一个负数 | 阻塞方法 |
int arriveAndDeregister() | 到达并且注销一个值 返回值同上 | 非阻塞方法 |
int awaitAdvance(int phase) | 等待当前相位器不是phase阶段的时候返回当前阶段 如果phase不为当前阶段,那么就不会阻塞 通常用来判断该阶段是否已经完成 | 根据参数 是否会发生阻塞 |
int awaitAdvanceInterruptibly(int phase)throws InterruptedException | 作用同上,但是能够响应中断 | |
int awaitAdvanceInterruptibly(int phase, long timeout, TimeUnit unit) throws InterruptedException, TimeoutException | 作用同上一个方法, 再这个基础上加上了时间限制 | |
int register() | 注册一个parties… 相位器的parties +1 返回值依然是 当前的相位 如果返回值是 一个负数 意味着 相位器已经终结 | |
int bulkRegister(int parties) | 作用同上一个方法, 批量注册 | parties如果为负数,会抛出异常 |
void forceTermination() | 关闭相位器 | 会造成所有子相位器或者父相位器全部关闭 |
int getPhase() | 返回当前相位器的 相位 | |
-----代码示例-----
-
实例化方法示例
package myConcurrent.s2020_03_27; import java.util.concurrent.Phaser; public class PhaserExample1 { public static void main(String[] args) throws InterruptedException { //演示实例化 Phaser phaser1 = new Phaser(); Phaser phaser2 = new Phaser(1); Phaser phaser3 = new Phaser(phaser2); Phaser phaser4 = new Phaser(phaser2,2); System.out.println(phaser1); System.out.println(phaser2); System.out.println(phaser3); System.out.println(phaser4); } }
-
测试 各种 arrive方法
package myConcurrent.s2020_03_27; import java.util.concurrent.Phaser; import java.util.concurrent.TimeUnit; public class PhaserExample2 { public static void main(String[] args) throws InterruptedException { final Phaser phaser = new Phaser(2); //测试arrive new ArriveThread(phaser); mySleep(1); //停顿一会 System.out.println("========================"); System.out.println("> 当前的相位 : " + phaser.getPhase()); new ArriveThread(phaser); mySleep(1); System.out.println("> 当前的相位 : " + phaser.getPhase()); //测试arriveAndWait new ArriveAndWaitThread(phaser); mySleep(1); System.out.println("========================"); new ArriveAndWaitThread(phaser); mySleep(1); System.out.println("> 当前的相位 : " + phaser.getPhase()); //测试arriveAndDeRegister System.out.println("> 当前的相位器注册了 : " + phaser.getRegisteredParties() +" 个部分"); new ArriveAndDeRegisterThread(phaser); mySleep(1); System.out.println("===================="); new ArriveAndDeRegisterThread(phaser); mySleep(1); System.out.println("> 当前的相位器注册了 : " + phaser.getRegisteredParties() +" 个部分"); } public static class ArriveAndDeRegisterThread extends Thread{ private final Phaser phaser; public ArriveAndDeRegisterThread(Phaser phaser) { this.phaser = phaser; this.start(); } @Override public void run() { phaser.arriveAndDeregister(); System.out.println("<< 我不会阻塞,而且能够取消掉一个注册信息!"); } } public static class ArriveAndWaitThread extends Thread{ private final Phaser phaser; public ArriveAndWaitThread(Phaser phaser) { this.phaser = phaser; this.start(); } @Override public void run() { phaser.arriveAndAwaitAdvance(); System.out.println("<< 我会和其他的线程一起输出~"); } } public static class ArriveThread extends Thread { private final Phaser phaser; public ArriveThread(Phaser phaser) { this.phaser = phaser; this.start(); } @Override public void run() { phaser.arrive(); System.out.println("<< 我没有被阻塞"); } } private static void mySleep(long seconds) throws InterruptedException { TimeUnit.SECONDS.sleep(seconds); } }
- 测试各种 awit 相关的方法
package myConcurrent.s2020_03_27;
import java.util.concurrent.Phaser;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.stream.IntStream;
//测试各种 await方法
public class PhaserExample3 {
public static void main(String[] args) throws InterruptedException {
Phaser phaser = new Phaser(2);
IntStream.range(0, 2).forEach(i -> {
new Thread(
() -> {
phaser.arrive();
System.out.println(i + " >> 已经完成了工作!");
}
).start();
});
int nowPhase = phaser.awaitAdvance(phaser.getPhase());
System.out.println("当前第一阶段工作已经完成!");
System.out.println("当前相位器的相位是 : " + nowPhase);
Thread dealWait = new Thread(
() -> {
try {
phaser.awaitAdvanceInterruptibly(phaser.getPhase());
} catch (InterruptedException e) {
System.out.println(">>> 等待能够响应中断");
}
}
);
dealWait.start();
mySleep(1);
dealWait.interrupt(); //尝试中断
try {
phaser.awaitAdvanceInterruptibly(phaser.getPhase(),2,TimeUnit.SECONDS);
} catch (TimeoutException e) {
System.out.println(">> 我能够等了一会就不等了");
}
}
private static void mySleep(long seconds) throws InterruptedException {
TimeUnit.SECONDS.sleep(seconds);
}
}
-
测试一些父子关系的相位器,以及相位器的关闭
package myConcurrent.s2020_03_27; import java.util.concurrent.Phaser; import java.util.concurrent.TimeUnit; import java.util.stream.IntStream; public class PhaserExample4 { public static void main(String[] args) throws InterruptedException { final Phaser phaser = new Phaser(2); final Phaser son = new Phaser(phaser, 2); // 子相位器的parties不为0 那么 父相位器的parties 会+1 System.out.println("father phaser is " + phaser.getRegisteredParties()); //phaser到达3次能够改变相位 System.out.println("father 当前相位是 " + phaser.getPhase()); IntStream.range(0, 3).forEach(i -> { phaser.arrive(); }); System.out.println("father 当前相位是 " + phaser.getPhase()); //子相位器相位改变一次, 父相位器的 到达数 能够增加1 System.out.println("father 当前的到达数是 " + phaser.getArrivedParties()); IntStream.range(0, 2).forEach(i -> { son.arrive(); }); System.out.println("father 当前的到达数是 " + phaser.getArrivedParties()); //子相位器相位改变一次 再arrive 会报错 try { IntStream.range(0, 3).forEach(i -> { son.arrive(); }); } catch (Exception e) { System.out.println(" 报错了!"); } //如果 线程 被阻塞的时候 终结 这个 相位器 //将会不等待 new Thread( phaser::arriveAndAwaitAdvance ).start(); TimeUnit.SECONDS.sleep(1); phaser.forceTermination(); //已经被终结的相位器,再arrive,其他操作都会无效 System.out.println(phaser); phaser.arriveAndDeregister(); System.out.println(phaser); } }
-
相位器模拟CountDownLatch
package myConcurrent.s2020_03_27; import java.util.concurrent.Phaser; import java.util.concurrent.TimeUnit; import java.util.stream.IntStream; public class PhaserExample5 { public static void main(String[] args) { final Phaser asCountDownLatch = new Phaser(3); IntStream.range(0, 3).forEach( i -> new Thread(() -> { System.out.println(i + "正在工作!"); try { TimeUnit.SECONDS.sleep(1); System.out.println(i + "工作完了"); asCountDownLatch.arrive(); } catch (InterruptedException e) { e.printStackTrace(); } }).start()); asCountDownLatch.awaitAdvance(asCountDownLatch.getPhase()); System.out.println("第一阶段的所有工作完成了!"); } }
-
模拟CyclicBarrier
package myConcurrent.s2020_03_27; import java.util.concurrent.Phaser; import java.util.stream.IntStream; public class PhaserExample6 { public static void main(String[] args) { final Phaser asCyclicBarrier = new Phaser(3); IntStream.range(0, 3).forEach( i -> new Thread( () -> { System.out.println(i + "完成工作! 等待其他的线程"); asCyclicBarrier.arriveAndAwaitAdvance(); System.out.println("屏障已经打开!"); } ).start() ); } }
~谢谢观看
来自一个萌新的日常总结
欢迎大佬来拍砖