这主要想写一下Java中的jdk提供的一些线程中的工具,
一、semaphore信号灯
Semaphore可以维护当前访问自身的线程个数,并提供了同步机制,使用Semaphore可以控制同时访问资源的线程的个数。例如,实现一个文件允许访问的并发数。
Semaphore实现的功能就类似厕所5个坑,假如有10个人要上厕所,那么同时可以有多少人上厕所呢?同时只能有5个人能够占用,当5个人中的任何一个让开后,其中在等待的另外5个中的一个就可以占用了。
单个信号量的Semaphore对象可以实现互斥锁的功能,并且可以是由一个线程获得了“锁”,再由另一个线程释放“锁”,这可应用于死锁恢复的一些场合。
代码如下:
1 importjava.util.concurrent.ExecutorService;2 importjava.util.concurrent.Executors;3 importjava.util.concurrent.Semaphore;4
5 /**
6 * @className: SemaphoreTest7 * @description: Semaphore信号灯测试实例8 *@author: ssc9 * @date: 2019年6月18日 下午9:01:3310 */
11 public classSemaphoreTest {12
13 public static voidmain(String[] args) {14
15 ExecutorService services =Executors.newCachedThreadPool();16 Semaphore sp = new Semaphore(3);17
18 for (int i = 0; i < 10; i++) {19 Runnable runnable = newRunnable() {20 @Override21 public voidrun() {22 try{23 //查询信号灯的状态 是否可以进入
24 sp.acquire();25 System.out.println("线程 " + Thread.currentThread().getName() + "进入,当前已有"
26 + (3 - sp.availablePermits()) + " 并发");27 Thread.sleep((long) (Math.random() * 10000));28 System.out.println("线程 " + Thread.currentThread().getName() + " 即将离开");29 //释放信号灯 让别的线程进入
30 sp.release();31 System.out.println("线程 " + Thread.currentThread().getName() + "已离开,当前已有"
32 + (3 - sp.availablePermits()) + " 并发");33 } catch(Exception e) {34 e.printStackTrace();35 }36 }37 };38 services.execute(runnable);39 }40 }41
42 }
二、CyclicBarrier循环路障
字面意思回环栅栏,通过它可以实现让一组线程等待至某个状态之后再全部同时执行。叫做回环是因为当所有等待线程都被释放以后,CyclicBarrier可以被重用。我们暂且把这个状态就叫做barrier,当调用await()方法之后,线程就处于barrier了。
使用代码如下:
1 importjava.util.concurrent.CyclicBarrier;2 importjava.util.concurrent.ExecutorService;3 importjava.util.concurrent.Executors;4
5 /**
6 * @className: CyclicBarrier7 * @description: 线程中的循环路障工具类8 *@author: ssc9 * @date: 2019年6月18日 下午9:58:3610 */
11 public classCyclicBarrierTest {12
13 public static voidmain(String[] args) {14 ExecutorService services =Executors.newCachedThreadPool();15 //创建 路障实例对象
16 CyclicBarrier cb = new CyclicBarrier(3);17
18 for (int i = 0; i < 3; i++) {19 Runnable runnable = newRunnable() {20 @Override21 public voidrun() {22 try{23
24 Thread.sleep((long) Math.random() * 10000);25 System.out.println("线程 " + Thread.currentThread().getName() + "即将到达集合地点1,当前已有"
26 + (cb.getNumberWaiting()) + " 到达,正在等候...");27 //到此如果没有达到公共屏障点,则该线程处于等待状态,如果达到公共屏障点则所有处于等待的线程都继续往下运行
28 cb.await();29
30 Thread.sleep((long) Math.random() * 10000);31 System.out.println("线程 " + Thread.currentThread().getName() + "即将到达集合地点2,当前已有"
32 + (cb.getNumberWaiting()) + " 到达,正在等候...");33 cb.await();34
35 Thread.sleep((long) Math.random() * 10000);36 System.out.println("线程 " + Thread.currentThread().getName() + "即将到达集合地点3,当前已有"
37 + (cb.getNumberWaiting()) + " 都到齐了, 继续走啊!");38 cb.await();39
40 } catch(Exception e) {41 e.printStackTrace();42 }43 }44 };45 services.execute(runnable);46 }47 services.shutdown();48 }49
50 }
三、CountDownLatch倒计时计时器
CountDownLatch犹如倒计时计时器,调用CountDownLatch对象的countDown方法就将计时器减去1。当计时器到达0时,则所有等待着或者单个等待着开始执行。
可以实现一个人或者是多个人等待其他人通知他,可以实现一个人通知多个人的效果。类似裁判一声口令,运动员同时开始奔跑,或者所有运动员都跑到终点后裁判才可以通知结果。还可以实现一个计划需要多个领导签字后才可以继续向下实施的情况
示例代码如下:
1 importjava.util.concurrent.CountDownLatch;2 importjava.util.concurrent.ExecutorService;3 importjava.util.concurrent.Executors;4
5 /**
6 * @className: CountDownLatchTest7 * @description: 线程中的计时器类8 *@author: ssc9 * @date: 2019年6月20日 下午9:13:4010 */
11 public classCountDownLatchTest {12
13 public static voidmain(String[] args) {14 ExecutorService services =Executors.newCachedThreadPool();15 //主线程中的计时器 相当于赛跑中的裁判
16 CountDownLatch cdOrder = new CountDownLatch(1);17 //新建线程的计时器 相当于赛跑中的运动员
18 CountDownLatch cdAnswer = new CountDownLatch(3);19
20 for (int i = 0; i < 3; i++) {21 Runnable runnable = newRunnable() {22 @Override23 public voidrun() {24 try{25 System.out.println("线程 " + Thread.currentThread().getName() + "正准备接受命令...");26 //等待计时器上技数值 归0 才开始执行 相当于运动员等待裁判的起跑枪声
27 cdOrder.await();28 System.out.println("线程 " + Thread.currentThread().getName() + "已经接受命令...");29 Thread.sleep((long) (Math.random() * 10000));30 System.out.println("线程 " + Thread.currentThread().getName() + "等待命令处理结果...");31 //计时器上的数值减去1 相当于运动员相继跑到终点 等待裁判宣布最终结果
32 cdAnswer.countDown();33 } catch(Exception e) {34 //TODO Auto-generated catch block
35 e.printStackTrace();36 }37 }38 };39 services.execute(runnable);40 }41 services.shutdown();42
43 try{44 Thread.sleep((long) (Math.random() * 10000));45 System.out.println("线程 " + Thread.currentThread().getName() + "即将发布命令...");46 //计数器上的 技数的值减去1 这个计数器本身就是 1 就相当于裁判的起跑枪声,只有这个计时器到0,其他线程才开始执行
47 cdOrder.countDown();48 System.out.println("线程 " + Thread.currentThread().getName() + "已经发布命令,正在等待结果...");49 //只有另外三个线程都执行到这里,分别将计时器的数值减去1,下面的代码才执行,相当于裁判等运动员都通过终点,才宣布结果
50 cdAnswer.await();51 System.out.println("线程 " + Thread.currentThread().getName() + "已收到所有响应结果...");52 } catch(Exception e) {53 e.printStackTrace();54 }55 }56 }
四、Exchanger工具类
用于实现两个人之间的数据交换,每个人在完成一件事物后,想与对方交换数据,第一个拿出数据的人将一直等待第二个人拿出数据来时,才会互相交换
示例代码如下:
1 importjava.util.concurrent.Exchanger;2 importjava.util.concurrent.ExecutorService;3 importjava.util.concurrent.Executors;4
5 /**
6 * @className: ExchangerTest7 * @description: Exchanger工具类的示例8 *@author: ssc9 * @date: 2019年6月20日 下午10:00:1910 */
11 public classExchangerTest {12
13 public static voidmain(String[] args) {14 ExecutorService services =Executors.newCachedThreadPool();15
16 Exchanger exchanger = newExchanger();17
18 services.execute(newRunnable() {19 @Override20 public voidrun() {21 try{22 String data1 = "abc";23 System.out.println("线程" + Thread.currentThread().getName() + "正准备把数据" + data1 + "换出去");24 Thread.sleep((long) (Math.random() * 10000));25 //进行数据的交换
26 String data2 =(String) exchanger.exchange(data1);27 System.out.println("线程" + Thread.currentThread().getName() + "换回的数据是" +data2);28 } catch(InterruptedException e) {29 //TODO Auto-generated catch block
30 e.printStackTrace();31 }32 }33 });34
35 services.execute(newRunnable() {36 @Override37 public voidrun() {38 try{39 String data1 = "edf";40 System.out.println("线程" + Thread.currentThread().getName() + "正准备把数据" + data1 + "换出去");41 Thread.sleep((long) (Math.random() * 10000));42 //进行数据的交换
43 String data2 =(String) exchanger.exchange(data1);44 System.out.println("线程" + Thread.currentThread().getName() + "换回的数据是" +data2);45 } catch(InterruptedException e) {46 //TODO Auto-generated catch block
47 e.printStackTrace();48 }49 }50 });51 services.shutdown();52 }53 }