编写一个程序,开启 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实践-线程按序交替执行的更多相关文章

  1. Java-JUC(十):线程按序交替执行

    问题: 有a.b.c三个线程,使得它们按照abc依次执行10次. 实现: package com.dx.juc.test; import java.util.concurrent.locks.Cond ...

  2. Java并发编程(二)如何保证线程同时/交替执行

    第一篇文章中,我用如何保证线程顺序执行的例子作为Java并发系列的开胃菜.本篇我们依然不会有源码分析,而是用另外两个多线程的例子来引出Java.util.concurrent中的几个并发工具的用法. ...

  3. java 面试题 -- 线程 按序 交替

    编写一个程序,开启 3 个线程,这三个线程的 ID 分别为A.B.C,每个线程将自己的 ID 在屏幕上打印 10 遍,要求输出的结果必须按顺序显示.如:ABCABCABC…… 依次递归? packag ...

  4. (三)juc高级特性——虚假唤醒 / Condition / 按序交替 / ReadWriteLock / 线程八锁

    8. 生产者消费者案例-虚假唤醒 参考下面生产者消费者案例: /* * 生产者和消费者案例 */ public class TestProductorAndConsumer { public stat ...

  5. 6.显示锁Lock 和 线程通信Condition

    显示锁 Lock 一.用于解决多线程 安全问题的方式: synchronized:   1.同步代码块      2.同步方法 jdk1.5 后:第三种:同步锁Lock  (注意:同步(synchro ...

  6. java中使用ReentrantLock锁中的Condition实现三个线程之间通信,交替输出信息

    本文直接附上源代码,如下是自己写的一个例子 面试题需求: 使用Condition来实现 三个线程 线程1 线程2 线程3 三个交替输出 [按照 线程1(main)-->线程2-->线程3] ...

  7. juc包:使用 juc 包下的显式 Lock 实现线程间通信

    一.前置知识 线程间通信三要素: 多线程+判断+操作+通知+资源类. 上面的五个要素,其他三个要素就是普通的多线程程序问题,那么通信就需要线程间的互相通知,往往伴随着何时通信的判断逻辑. 在 java ...

  8. 简单的线程同步问题:两个线程交替执行N次【Synchronized、Lock、ArrayBlockingQueue】

    方法一:传统的线程方法import org.apache.log4j.Logger; /** * 两个线程执行的代码片段要实现同步互斥的效果,它们必须用同一个Lock对象.<br/> * ...

  9. JUC.Condition学习笔记[附详细源码解析]

    目录 Condition的概念 大体实现流程 I.初始化状态 II.await()操作 III.signal()操作 3个主要方法 Condition的数据结构 线程何时阻塞和释放 await()方法 ...

随机推荐

  1. Petri网

    Petri网是一种适合于系统描述和分析的数学模型,主要描述异步和并发关系.(或者Petri网是对离散并行系统的数学表示,适用于描述异步的,并发的计算机系统模型.) Petri网模型自然,直观,简单易懂 ...

  2. [转]用 jQuery 实现页面滚动(Scroll)效果的完美方法

    转自: http://zww.me/archives/25144 很多博主都写过/转载过用 jQuery 实现页面滚动(Scroll)效果的方法,但目前搜来的方法大都在 Opera 下有个小 Bug: ...

  3. HTTP和HTTPS的区别(转)

    原文链接:HTTP和HTTPS的区别 HTTPS(Secure Hypertext Transfer Protocol)安全超文本传输协议 它是一个安全通信通道,它基于HTTP开发,用于在客户计算机和 ...

  4. BMap:WEB 服务API

    ylbtech-Map-Baidu: WEB 服务API 百度地图Web服务API为开发者提供http/https接口,即开发者通过http/https形式发起检索请求,获取返回json或xml格式的 ...

  5. OpenCV教程(48) 特征值匹配

          OpenCV中通过下面的代码,可以匹配两幅的图像的特征值. // Read input images cv::Mat image1= cv::imread("../church0 ...

  6. 样条之埃特金(Aitken)逐步插值函数

    核心代码: ////////////////////////////////////////////////////////////////////// // 埃特金逐步插值 //////////// ...

  7. iOS 加密的3种方法

    //需要导入   #import <CommonCrypto/CommonCryptor.h> ==============MD5加密============ NSString *str ...

  8. cesium原理篇(二)--网格划分【转】

    转自:http://www.cnblogs.com/fuckgiser/p/5772077.html 上一篇我们从宏观上介绍了Cesium的渲染过程,本章延续上一章的内容,详细介绍一下Cesium网格 ...

  9. 【R】自定义函数方法

  10. xshell tunnel的使用

    原文:https://www.jianshu.com/p/388a93b1e7f7 https://blog.csdn.net/qq_34039315/article/details/77510923 ...