package cn.itcast.thread;import java.util.concurrent.Semaphore;import java.util.concurrent.TimeUnit;public class Test18 {public static void main(String[] args) {// 1. 创建信号量对象控制并发线程数量 , 设置许可数5个(同时运行5个线程)Semaphore semaphore = new Semaphore(5, true);// 2. 循环运行10个线程(会看到每次只允许5个线程)for (int i = 0; i < 10; i++) {new Thread(() -> {try {// 2.1 申请获取许可semaphore.acquire();// 2.2 运行业务System.out.println(Thread.currentThread().getName() + "车,进入停车场");TimeUnit.SECONDS.sleep(3);// 让当前线程休眠(让线程多运行一会,方便观察效果)System.out.println(Thread.currentThread().getName() + "车,离开停车场");// 2.3 释放阻塞,增加一个许可(让下一个阻塞的线程运行)semaphore.release();} catch (Exception e) {e.printStackTrace();}}).start();}}} 运行效果
文章插图
特点
Semaphore 在计数器不为 0 的时候对线程就放行,一旦达到 0,那么所有请求资源的新线程都会被阻塞,包括增加请求到许可的线程,Semaphore 是不可重入的 。
- 每一次请求一个许可都会导致计数器减少 1,同样每次释放一个许可都会导致计数器增加 1,一旦达到 0,新的许可请求线程将被挂起 。
- 公平模式就是调用 acquire 的顺序就是获取许可证的顺序,遵循 FIFO 。
Semaphore semaphore = new Semaphore(许可数, true); // 公平模式- 非公平模式是抢占式的,也就是有可能一个新的获取线程恰好在一个许可证释放时得到了这个许可证 , 而前面还有等待的线程 。
Semaphore semaphore = new Semaphore(许可数, false); // 非公平模式,(默认) 小结- Semaphore 的使用(3个操作)
– 增加许可,release()方法释放一个阻塞,增加一个许可 。
– 获取许可,acquire()方法获取许可 , 再获取许可前处于阻塞等待 。20、并发工具类:Exchanger(交换数据)目标:掌握Exchanger的使用
介绍
Exchanger(交换者)是一个用于线程间协作的工具类 , 可以用于进行线程间的数据交换 。
交换数据原理
- Exchanger提供一个同步点 , 在这个同步点两个线程可以交换彼此的数据 。
- 两个线程通过 exchange() 方法交换数据 。
- 第一个线程先执行 exchange() 方法,会一直等待第二个线程也执行exchange()到达同步点时,两个线程交换数据,将本线程生产出来的数据传递给对方 。
- 使用 Exchanger 的重点是用对的线程使用 exchange() 方法 。

文章插图
API方法
package cn.itcast.thread;import java.util.concurrent.Exchanger;public class Test19 {public static void main(String[] args) {// 1. 创建交换数据对象,并设置传输数据的类型Exchanger<String> exchanger = new Exchanger<>();// 2. 启动2个线程进行交换数据// 创建线程1new Thread(() -> {// 2.1 定义交换的数据String girl1 = "【柳岩】";System.out.println(Thread.currentThread().getName() + "说:我的女友 " + girl1);System.out.println(Thread.currentThread().getName() + "说:等待线程2交换数据");// 2.2 将数据交换给线程2,并拿到线程2的数据try {String b = exchanger.exchange(girl1);//注意:如果线程2没有到达同步点,当前线程会被阻塞一直等到//成功获取线程2的数据后System.out.println(Thread.currentThread().getName() + "说:我拿到了 " + b);} catch (InterruptedException e) {e.printStackTrace();}}).start();// 创建线程2new Thread(()->{// 2.3 定义交换的数据String girl2 = "【杨幂】";System.out.println(Thread.currentThread().getName()+"说:我的女友 " + girl2);System.out.println(Thread.currentThread().getName()+"说:等待线程1交换数据");// 2.4 将数据交换给线程1,并拿到线程1的数据try {String a = exchanger.exchange(girl2);// 成功获取线程1的数据后System.out.println(Thread.currentThread().getName()+"说:我拿到了 " + a);} catch (InterruptedException e) {e.printStackTrace();}}).start();}}
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- “正科级”公务员退休后有多少钱?40年工龄的话,预计是这个数
- 女人对你有好感,哪怕嘴上不说,这7个肢体语言也藏不住
- “无性婚姻”有多可怕?听听3个过来人的故事,希望你能引以为戒
- 家里放了几年的红茶、绿茶、普洱茶,还能喝吗?医生告诉你实话
- 求求你们别再换脸了,就像好好的一盘菜吃出苍蝇的感觉!
- 拒认儿子巴图20年,晚年态度翻转,是居心叵测,还是真后悔?
- 教你自己制作花生酱,教你自制花生酱
- 微博该咋得才可以删除评论,为什么微博评论删除后还有显示
- 《我知道我爱你》热播:和冬天适配的偶像剧
- 李善均离世早有端倪?留下遗书后离家,现场有点燃闪电弹的痕迹
