JUC-Condition和Lock实践-线程按序交替执行
编写一个程序,开启 3 个线程,这三个线程的 ID 分别为 A、B、C,每个线程将自己的 ID 在屏幕上打印 10 遍,要求输出的结果必须按顺序显示。
如:ABCABCABC…… 依次递归
这里只使用conditon和Lock组合使用,不考虑synchronized和wait的方式:
第一种方式:使用一个condition,跟while条件组合。
通过signalAll,每次执行完唤醒所有的线程。
每个线程唤醒后,是否阻塞通过while里面的变量值来决定:
package com.atguigu.juc; import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; /*
* 编写一个程序,开启 3 个线程,这三个线程的 ID 分别为 A、B、C,每个线程将自己的 ID 在屏幕上打印 10 遍,要求输出的结果必须按顺序显示。
* 如:ABCABCABC…… 依次递归
*/
public class TestABCAlternate { public static void main(String[] args) {
AlternateDemo ad = new AlternateDemo(); new Thread(new Runnable() {
@Override
public void run() { //注意:各个线程的循环次数必须相等,否则当一个线程唤醒另一个Condition的时候,对应
//唤醒锁所在的线程已经执行完了,此时就会一直等待,而其他没执行完的线程则一直阻塞。
for (int i = 1; i <= 20; i++) {
ad.loopA(i);
} }
}, "A").start(); new Thread(new Runnable() {
@Override
public void run() { for (int i = 1; i <= 20; i++) {
ad.loopB(i);
} }
}, "B").start(); new Thread(new Runnable() {
@Override
public void run() { for (int i = 1; i <= 20; i++) {
ad.loopC(i); System.out.println("-----------------------------------");
}
}
}, "C").start();
}
} class AlternateDemo{ private int number = 1; //当前正在执行线程的标记 private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
/**
* @param totalLoop : 循环第几轮
*/
public void loopA(int totalLoop){
lock.lock(); try {
//1. 判断,如果number不为1,则该线程阻塞
while(number != 1){
condition.await();
}
//2. 打印
for (int i = 1; i <= 1; i++) {
System.out.println(Thread.currentThread().getName() + "\t" + i + "\t" + totalLoop);
} //3. 修改值来决定哪个线程能够下一个执行,并且唤醒所有的线程。
number = 2;
condition.signalAll();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
} public void loopB(int totalLoop){
lock.lock();
try {
//1. 判断
while(number != 2){
condition.await();
}
//2. 打印
for (int i = 1; i <= 1; i++) {
System.out.println(Thread.currentThread().getName() + "\t" + i + "\t" + totalLoop);
}
//3. 唤醒
number = 3;
condition.signalAll();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
} public void loopC(int totalLoop){
lock.lock(); try {
//1. 判断
while(number != 3){
condition.await();
}
//2. 打印
for (int i = 1; i <= 1; i++) {
System.out.println(Thread.currentThread().getName() + "\t" + i + "\t" + totalLoop);
}
//3. 唤醒
number = 1;
condition.signalAll();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
运行结果:

第二种方式:每个线程分配一个condition对象,与if组合。
1,通过conditionA.signal()来唤醒conditionA所wait的线程,这种方式可以指定唤醒哪个线程,以此来实现线程间通信。
所以不会出现唤醒其他错误的线程,而需要通过while循环判断的情况,只需要if即可。
2,定义一个变量的值,通过改变这个变量的值,来决定究竟当前线程是否进入等待。
例如,这里有三个线程,则需要三个condition对象,每个condition对象分别分配到不同的线程运算里面,进行await,signal等操作,
通过不同condition对象之间的相互通信,互相唤醒。
private Lock lock = new ReentrantLock();
private Condition condition1 = lock.newCondition();
private Condition condition2 = lock.newCondition();
private Condition condition3 = lock.newCondition();
实现代码:
package com.atguigu.juc; import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; /*
* 编写一个程序,开启 3 个线程,这三个线程的 ID 分别为 A、B、C,每个线程将自己的 ID 在屏幕上打印 10 遍,要求输出的结果必须按顺序显示。
* 如:ABCABCABC…… 依次递归
*/
public class TestABCAlternate { public static void main(String[] args) {
AlternateDemo ad = new AlternateDemo(); new Thread(new Runnable() {
@Override
public void run() { //注意:各个线程的循环次数必须相等,否则当一个线程唤醒另一个Condition的时候,对应
//唤醒锁所在的线程已经执行完了,此时就会一直等待,而其他没执行完的线程则一直阻塞。
for (int i = 1; i <= 20; i++) {
ad.loopA(i);
} }
}, "A").start(); new Thread(new Runnable() {
@Override
public void run() { for (int i = 1; i <= 20; i++) {
ad.loopB(i);
} }
}, "B").start(); new Thread(new Runnable() {
@Override
public void run() { for (int i = 1; i <= 20; i++) {
ad.loopC(i); System.out.println("-----------------------------------");
} }
}, "C").start();
} } class AlternateDemo{ private int number = 1; //当前正在执行线程的标记 private Lock lock = new ReentrantLock();
private Condition condition1 = lock.newCondition();
private Condition condition2 = lock.newCondition();
private Condition condition3 = lock.newCondition(); /**
* @param totalLoop : 循环第几轮
*/
public void loopA(int totalLoop){
lock.lock(); try {
//1. 判断
if(number != 1){
condition1.await();
} //2. 打印
for (int i = 1; i <= 1; i++) {
System.out.println(Thread.currentThread().getName() + "\t" + i + "\t" + totalLoop);
} //3. 修改number值,唤醒condition2的等待线程,使得condition2.await()后面的代码继续执行
number = 2;
condition2.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
} public void loopB(int totalLoop){
lock.lock(); try {
//1. 判断
if(number != 2){
condition2.await();
} //2. 打印
for (int i = 1; i <= 1; i++) {
System.out.println(Thread.currentThread().getName() + "\t" + i + "\t" + totalLoop);
} //3. 唤醒
number = 3;
condition3.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
} public void loopC(int totalLoop){
lock.lock(); try {
//1. 判断
if(number != 3){
condition3.await();
} //2. 打印
for (int i = 1; i <= 1; i++) {
System.out.println(Thread.currentThread().getName() + "\t" + i + "\t" + totalLoop);
} //3. 唤醒
number = 1;
condition1.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
执行结果:

JUC-Condition和Lock实践-线程按序交替执行的更多相关文章
- Java-JUC(十):线程按序交替执行
问题: 有a.b.c三个线程,使得它们按照abc依次执行10次. 实现: package com.dx.juc.test; import java.util.concurrent.locks.Cond ...
- Java并发编程(二)如何保证线程同时/交替执行
第一篇文章中,我用如何保证线程顺序执行的例子作为Java并发系列的开胃菜.本篇我们依然不会有源码分析,而是用另外两个多线程的例子来引出Java.util.concurrent中的几个并发工具的用法. ...
- java 面试题 -- 线程 按序 交替
编写一个程序,开启 3 个线程,这三个线程的 ID 分别为A.B.C,每个线程将自己的 ID 在屏幕上打印 10 遍,要求输出的结果必须按顺序显示.如:ABCABCABC…… 依次递归? packag ...
- (三)juc高级特性——虚假唤醒 / Condition / 按序交替 / ReadWriteLock / 线程八锁
8. 生产者消费者案例-虚假唤醒 参考下面生产者消费者案例: /* * 生产者和消费者案例 */ public class TestProductorAndConsumer { public stat ...
- 6.显示锁Lock 和 线程通信Condition
显示锁 Lock 一.用于解决多线程 安全问题的方式: synchronized: 1.同步代码块 2.同步方法 jdk1.5 后:第三种:同步锁Lock (注意:同步(synchro ...
- java中使用ReentrantLock锁中的Condition实现三个线程之间通信,交替输出信息
本文直接附上源代码,如下是自己写的一个例子 面试题需求: 使用Condition来实现 三个线程 线程1 线程2 线程3 三个交替输出 [按照 线程1(main)-->线程2-->线程3] ...
- juc包:使用 juc 包下的显式 Lock 实现线程间通信
一.前置知识 线程间通信三要素: 多线程+判断+操作+通知+资源类. 上面的五个要素,其他三个要素就是普通的多线程程序问题,那么通信就需要线程间的互相通知,往往伴随着何时通信的判断逻辑. 在 java ...
- 简单的线程同步问题:两个线程交替执行N次【Synchronized、Lock、ArrayBlockingQueue】
方法一:传统的线程方法import org.apache.log4j.Logger; /** * 两个线程执行的代码片段要实现同步互斥的效果,它们必须用同一个Lock对象.<br/> * ...
- JUC.Condition学习笔记[附详细源码解析]
目录 Condition的概念 大体实现流程 I.初始化状态 II.await()操作 III.signal()操作 3个主要方法 Condition的数据结构 线程何时阻塞和释放 await()方法 ...
随机推荐
- Secondary NameNode 的作用
https://blog.csdn.net/xh16319/article/details/31375197 很多人都认为,Secondary NameNode是NameNode的备份,是为了防止Na ...
- Ubuntu sh命令无法正确执行 (修改默认sh为bash)
新安装的ubuntu,执行shell命令,都怀疑自己的shell水平了. 原来, ubuntu默认的是dash, 需要手动执行命令将dash改为bash. 命令: sudo dpkg-reconfig ...
- Android开发者选项 介绍
15个必知的Android开发者选项 https://www.jianshu.com/p/07b551ee260b 1.Stay awake 充电时保持屏幕唤醒,开发的时候,时不时的锁屏真是够了,开 ...
- Limu:有关JavaScript的那些值得一看的书
来源&作者:Limu 又好久没写东西了 ,写上一篇的时候还以为接下来的工作会轻松一些 ,结果未从我所愿呐 ,又是一阵忙碌.而这段时间穿插着做了很多12年淘宝校园招聘的前端面试 ,很多同学都有问 ...
- 梯度消失(vanishing gradient)与梯度爆炸(exploding gradient)问题
(1)梯度不稳定问题: 什么是梯度不稳定问题:深度神经网络中的梯度不稳定性,前面层中的梯度或会消失,或会爆炸. 原因:前面层上的梯度是来自于后面层上梯度的乘乘积.当存在过多的层次时,就出现了内在本质上 ...
- Topic Model的分类和设计原则
Topic Model的分类和设计原则 http://blog.csdn.net/xianlingmao/article/details/7065318 topic model的介绍性文章已经很多,在 ...
- RAMPS1.4 3d打印控制板接线与测试2
http://learn.makerlab.me/guides/1/articles/2 mega 2560板子在3d打印机中相当于大脑,控制这所有的3d打印配件来完成复杂的打印工作,但mega256 ...
- [Node.js] process.nextTick for converting sync to async
For example we have a function to check the filesize: const fs = require('fs'); function fileSize (f ...
- 一个WEB应用的开发流程
转载:http://www.51testing.com/html/56/n-3721856.html 先说项目开发过程中团队人员的分工协作. 一.人员安排 毕业至今的大部分项目都是独立完成,虽然也有和 ...
- (纪录片)你必须知道的科学 The Science That You Have To Know (2014)
简介: 类型: 纪录片制片国家/地区: 英国语言: 英语上映日期: 2014-2片长: 150分钟 主要内容: 你有没有认真想过,自己的身体有多奇妙?人体是世间最复杂的一项工程杰作,他也带来了一些非常 ...