您现在的位置是:首页 > 文章详情

8.JUC线程高级-Condition和线程顺序执行

日期:2018-09-04点击:386

有的时候我们希望线程按照希望的顺序依次执行,比如线程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(); 

要求

  1. 创建一个TestAlternate类,有三个方法loopA(),loopB(),loopC(),分别打印A,B,C
  2. 主函数中创建三个线程,绑定三个匿名类实现Runnable接口
  3. 主函数中循环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 

虚假唤醒的注意事项

出现虚假唤醒的原因
假如A1A2两个线程争夺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的值是否正确,保证了程序的正常运行,避免虚假唤醒的情况出现。

原文链接:https://yq.aliyun.com/articles/636321
关注公众号

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。

持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。

转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。

文章评论

共有0条评论来说两句吧...

文章二维码

扫描即可查看该文章

点击排行

推荐阅读

最新文章