8.JUC线程高级-Condition和线程顺序执行
有的时候我们希望线程按照希望的顺序依次执行,比如线程A,B,C,按照顺序依次执行,这时候就要用到阻塞和唤醒,之前的时候我们学到过wait()
和nofity/notifyAll()
这两个方法,这里我们使用java.concurrent.locks.Lock
接口来实现类似的功能;
用到的包和类
java.concurrent.locks.Lock:接口 |-->java.concurrent.locks.ReentrantLock:实现类 |-->java.util.concurrent.locks.Condition:抽象类
方法:
Lock lock = new ReentrantLock(); Condition condition = lock.newCondition();
要求
- 创建一个TestAlternate类,有三个方法loopA(),loopB(),loopC(),分别打印A,B,C
- 主函数中创建三个线程,绑定三个匿名类实现Runnable接口
- 主函数中循环10次,使得每次打印都按照A–>B–>C的顺序来打印
创建类
TestAlternate.java
class TestAlternate{ //线程执行顺序标记,1:表示loopA执行,2:表示loopB执行,3:表示loopC执行 private volatile int number = 1; //获得lock锁 private Lock lock = new ReentrantLock(); //创建三个condition对象用来await(阻塞)和signal(唤醒)指定的线程 private Condition c1 = lock.newCondition(); private Condition c2 = lock.newCondition(); private Condition c3 = lock.newCondition(); protected void loopA(){ lock.lock();//上锁 try { /*如果不是第一个标志位,就阻塞,为了解决虚假唤醒问题,使用while关键字 */ while(number!=1){ try { c1.await();//阻塞类似wait() } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(Thread.currentThread().getName()+"-A"); number = 2;//使能第二个方法 c2.signal();//唤醒第二个线程,类似notify()方法 } finally { lock.unlock();//解锁 } } protected void loopB(){ lock.lock();//上锁 try { //如果不是第一个标志位,就阻塞 while(number!=2){ try { c2.await();//阻塞类似wait() } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(Thread.currentThread().getName()+"-B"); number = 3;//使能第3个方法 c3.signal();//唤醒第三个线程,类似notify()方法 } finally { lock.unlock();//解锁 } } protected void loopC(){ lock.lock();//上锁 try { //如果不是第一个标志位,就阻塞 while(number!=3){ try { c3.await();//阻塞类似wait() } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(Thread.currentThread().getName()+"-C"); number = 1;//使能第1个方法 c1.signal();//唤醒第一个线程,类似notify()方法 } finally { lock.unlock();//解锁 } } }
测试输出:
loopA0-A loopB0-B loopC0-C loopA1-A loopB1-B loopC1-C loopC2-C//虚假唤醒问题 loopA2-A loopB2-B
虚假唤醒的注意事项
出现虚假唤醒的原因:
假如A1,A2两个线程争夺loopA,A2夺得了cpu执行权,结果发现此时A2的标记为number不是1,于是await,A2开始阻塞这个时候释放锁和资源,然后B,C线程得到cpu执行权按照顺序执行完毕,此时A的标志位是1,此时A1和A2的锁都是c2.await()A1,A2同时被被唤醒,A1抢到了cpu执行权,打印输出loopA,并改变number为2,然后由于A2也被唤醒,但是由于是if
语句,在阻塞前只判断了一次,即便此时number不是2了,但是A2不会再次判断number的值,继续往下执行,导致重复输出loopA
。
解决方案:
把if
替换为while
,使得每次都判断number的值是否正确,保证了程序的正常运行,避免虚假唤醒的情况出现。

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
编写灵活、稳定、高质量的CSS代码的规范(推荐收藏)
一、唯一定律 无论有多少人共同参与同一项目,一定要确保每一行代码都像是唯一个人编写的。 二、HTML 2.1 语法 (1)用两个空格来代替制表符(tab) -- 这是唯一能保证在所有环境下获得一致展现的方法。 (2)嵌套元素应当缩进一次(即两个空格)。 (3)对于属性的定义,确保全部使用双引号,绝不要使用单引号。 (4)不要在自闭合(self-closing)元素的尾部添加斜线 -- HTML5 规范中明确说明这是可选的。 (5)不要省略可选的结束标签(closing tag)(例如,</li> 或 </body>)。 2.2 Example 三、HTML5 doctype 为每个 HTML 页面的第一行添加标准模式(standard mode)的声明,这样能够确保在每个浏览器中拥有一致的展现。 四、语言属性 根据 HTML5 规范: 强烈建议为 html 根元素指定 lang 属性,从而为文档设置正确的语言。这将有助于语音合成工具确定其所应该采用的发音,有助于翻译工具确定其翻译时所应遵守的规则等等。 五、IE 兼容模式 IE 支持通过特定的 <meta&...
- 下一篇
对比来了!Julia 能打败 Python 和 R 成最终赢家吗?
在这篇文章中,作者通过一个简单的似然函数优化(Maximum Likelihood Optimization)问题来对比 Julia,R 和 Python。这是一个比较小的优化问题,性能上的差异表现可能不太明显,但解决问题的过程能很好地反应三者各自的优劣势。 作者在撰写本文时,对这三种语言的熟悉程度如下: Julia 布道者 ChrisRackauckas 曾经说过: 如果你用 Julia 处理一个 10 秒内的问题,它的优势并不能体现出来。 而一旦处理的问题变复杂,需要花费比较长的时间,这时 Julia 的优势就会慢慢体现了。 有人用 Python 和 Julia 做过对比实验。以 10⁵ 为界点进行计算,当数值比 10⁵ 更小时 Python 比 Julia 快的。但数值大于 10⁵ 后,Julia 的速度就比 Python 快很多了。 优化问题 观察序列 Q1,Q2,...,Qn,我们需要找到优化该似然函数的参数 μ 和 σ: 通常我们会尝试优化对数似然: 在统计学上,这是截断的正态分布的最大似然估计(MLE)。 Julia 的测试情况 以下是作者使用 Julia 进行测试的情况...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS7,CentOS8安装Elasticsearch6.8.6
- CentOS7,8上快速安装Gitea,搭建Git服务器
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- SpringBoot2初体验,简单认识spring boot2并且搭建基础工程
- CentOS关闭SELinux安全模块
- Linux系统CentOS6、CentOS7手动修改IP地址
- Windows10,CentOS7,CentOS8安装Nodejs环境
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装