【JUC并发编程04】线程间定制化通信(单标志法存在的问题)
2022/1/31 17:40:38
本文主要是介绍【JUC并发编程04】线程间定制化通信(单标志法存在的问题),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
文章目录
- 4 线程间定制化通信
- 案例实现
- 该案例需要注意
4 线程间定制化通信
案例实现
案列:启动三个线程,按照如下要求:
AA打印5此,BB打印10次,CC打印15次,一共进行10轮
具体思路:
每个线程添加一个标志位,是该标志位则执行操作,并且修改为下一个标志位,通知下一个标志 位的线程
创建一个可重入锁 private Lock lock = new ReentrantLock();
分别创建三个开锁通知 private Condition c1 = lock.newCondition();
(他们能实现指定唤醒)
(注意)具体资源类中的A线程代码操作
上锁,(执行具体操作(判断、操作、通知),解锁)放于try、finally,具体代码如下
class Share{ private int flag = 1; private Lock lock = new ReentrantLock(); // 创建三个Comdition对象,为了定向唤醒相乘 Condition c1 = lock.newCondition(); Condition c2 = lock.newCondition(); Condition c3 = lock.newCondition(); public void Aprint(int loop) { //上锁 lock.lock(); try{ // 判断 while(flag!=1) { c1.await(); } // 干活 for (int i = 1; i <= 5; i++) { System.out.println(Thread.currentThread().getName() + " ::本次第" + i + "次打印,是第" + loop+ "次循环"); } flag = 2; //修改标志位,定向唤醒 线程b // 唤醒 c2.signal(); } catch (InterruptedException e) { e.printStackTrace(); } finally { // 解锁 lock.unlock(); } } public void Bprint(int loop) { //上锁 lock.lock(); try{ // 判断 while(flag!=2) { c2.await(); } // 干活 for (int i = 1; i <= 10; i++) { System.out.println(Thread.currentThread().getName() + " ::本次第" + i + "次打印,是第" + loop+ "次循环"); } flag = 3; //修改标志位,定向唤醒 线程b // 唤醒 c3.signal(); } catch (InterruptedException e) { e.printStackTrace(); } finally { // 解锁 lock.unlock(); } } public void Cprint(int loop) { //上锁 lock.lock(); try{ // 判断 while(flag!=3) { c3.await(); } // 干活 for (int i = 1; i <= 15; i++) { System.out.println(Thread.currentThread().getName() + " ::本次第" + i + "次打印,是第" + loop+ "次循环"); } flag = 1; //修改标志位,定向唤醒 线程b // 唤醒 c1.signal(); } catch (InterruptedException e) { e.printStackTrace(); } finally { // 解锁 lock.unlock(); } } } public class CustomInterThreadCommunication { public static void main(String[] args) { Share share = new Share(); new Thread(new Runnable() { @Override public void run() { for (int i = 1; i <= 10; i++) { share.Aprint(i); } } },"A").start(); new Thread(new Runnable() { @Override public void run() { for (int i = 1; i <= 10; i++) { share.Bprint(i); } } },"B").start(); new Thread(new Runnable() { @Override public void run() { for (int i = 1; i <= 100; i++) { share.Cprint(i); } } },"C").start(); } }
测试结果如下:
该案例需要注意
我们在学习操作系统中的同步可以知道,进程/线程同步有四个原则,都是为了禁止两个进程同时进入临界区。同步机制应该遵循以下原则
- 空闲让进:临界区空闲时,可以允许一个请求进入临界区的进程立即进入临界区
- 忙则等待:当已经有进程进入临界区的时候,其他试图进入临界区的进程必须等待
- 有限等待:对请求访问的进程,应保证能在有限时间内进入临界区
- 让权等待:当进程不能进入临界区的时候,应立即释放处理机,防止进程忙等待
很显然,该案例被称为单标志法。因为该案例设置一个公用整型变量flag,用于指示被允许进入临界区的进程编号。
若 flag =1,则允许 P 1 P_1 P1 进程进入临界区;若 flag =2,则允许 P 2 P_2 P2 进程进入临界区;若 flag =3,则允许 P 3 P_3 P3 进程进入临界区
该算法可确保每次只允许一个进程进入临界区。
但两个进程必须交替进入临界区,若某个进程不再进入临界区,则另一个进程也无法进入临界区
比如,若 P 3 P_3 P3 顺利进入临界区并从临界区离开,则此时临界区是空闲的,但 P 1 P_1 P1 并没有进入临界区的打算,flag = 1 一直成立, P 3 P_3 P3 就无法再次进入临界区。
违背了"空闲让进"原则,让资源利用不充分·
比如,将上述代码中的 main() 方法的C线程从10 改为 20 ,C线程不能访问 Share 资源了,因为 A 线程已经不再访问同时 flag 值不再改变了。
单标志法伪代码如下
//P_0进程 while(turn!=0); critical section; turn=1; remainder section;
//P_1进程 while(turn!=1); critical section; turn=0; remainder section;
这篇关于【JUC并发编程04】线程间定制化通信(单标志法存在的问题)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-23增量更新怎么做?-icode9专业技术文章分享
- 2024-11-23压缩包加密方案有哪些?-icode9专业技术文章分享
- 2024-11-23用shell怎么写一个开机时自动同步远程仓库的代码?-icode9专业技术文章分享
- 2024-11-23webman可以同步自己的仓库吗?-icode9专业技术文章分享
- 2024-11-23在 Webman 中怎么判断是否有某命令进程正在运行?-icode9专业技术文章分享
- 2024-11-23如何重置new Swiper?-icode9专业技术文章分享
- 2024-11-23oss直传有什么好处?-icode9专业技术文章分享
- 2024-11-23如何将oss直传封装成一个组件在其他页面调用时都可以使用?-icode9专业技术文章分享
- 2024-11-23怎么使用laravel 11在代码里获取路由列表?-icode9专业技术文章分享
- 2024-11-22怎么实现ansible playbook 备份代码中命名包含时间戳功能?-icode9专业技术文章分享