控制多线程的打印顺序---交替打印(3种方式)
方法1:
package com.itheima.bookcurrentment;
分析:
/*
前提:线程123分别输出abc
需求:交替打印abc5次,打印结果示例:abcabcabcabc…
思路:用同步方法,定义多个条件,满足条件时打印,不满足时进入wait等待
设置一个整数,当数为1时打印1,当不是1时(相当于条件不满足)则进入wait等待
输出内容等待标记下一个标记
a12
b23
c31
*/
@Slf4j(topic = "c.TestPrint1")
public class TestPrint1 {
public static void main(String[] args) {
//测试:由于要共用同一个WaitNotify对象,因此先创建一个WaitNotify对象,以便后面对它进行加锁
// 创建三个线程,在这个三个线程中调用打印方法,并且在该方法中指定打印内容,等待标记(公共标记与这个等待标记一致则打印内容),以及下一个标记
WaitNotify waitNotify=new WaitNotify(1,5);
//初始标记为1,循环次数是5
new Thread(()->{
try {
waitNotify.print("a",1,2);
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
new Thread(()->{
try {
waitNotify.print("b",2,3);
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
new Thread(()->{
try {
waitNotify.print("c",3,1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
}class WaitNotify{//打印方法,该方法由不同的线程调用,不同线程输出的内容,等待标记和下一个标记都不相同,因此将这三个值作为参数
public voidprint(String str,int waitFlag,int nextFlag) throws InterruptedException {
//打印逻辑:加锁,先获取到调用线程的标记,与公共标记相比较,相等则继续打印相应内容,
// 并设置下一个标记(唤醒下一个线程),不相等则进入阻塞
for(int i=0;
i
打印结果:abcabcabcabcabc
关键点:使用了一个整数标记来判断是应该等待还是继续向下运行,并且使用了下一个等待标记控制接下来应该是哪一个线程放弃等待,执行打印。
方法2:使用ReentrantLock实现,充分利用这个锁的特点----它的条件变量(休息室)可以有多个
@Slf4j(topic = "c.TestPrint2")
public class TestPrint2 {
public static void main(String[] args) throws InterruptedException {
AwaitSignal awaitSignal=new AwaitSignal(5);
//创建了3个休息室
Condition a=awaitSignal.newCondition();
Condition b=awaitSignal.newCondition();
Condition c=awaitSignal.newCondition();
new Thread(()->{
awaitSignal.print("a",a,b);
//该线程打印a,打印之前首先进入休息室a等待,当它执行完成后要唤醒b休息室的线程}).start();
new Thread(()->{
awaitSignal.print("b",b,c);
//该线程打印b,打印之前首先进入休息室b等待,当它执行完成后要唤醒的c休息的线程
}).start();
new Thread(()->{
awaitSignal.print("c",c,a);
//该线程打印c,打印之前首先进入休息室b等待,当它执行完成后要唤醒的a休息室的线程}).start();
//由于这三个线程一启动都进入了休息室等待,因此需要一个线程先唤醒a休息室中的线程
TimeUnit.SECONDS.sleep(1);
awaitSignal.lock();
//获取锁
try{
log.debug("由主线程开始唤醒a线程后,,,,开始。。。。。。。。");
a.signal();
//唤醒a休息室的线程
}finally {
awaitSignal.unlock();
//释放锁
}
}
}class AwaitSignal extends ReentrantLock{
private int loopNumber;
public AwaitSignal(int loopNumber) {
this.loopNumber = loopNumber;
}//写一个print,由三个线程调用,当不满足条件时进入格各自的休息室等待
//参数1:打印的内容,参数2,进入哪一间休息室,参数3,表示下一件休息室
public void print(String str,Condition current,Condition next){
for(int i=0;
i
打印结果:
19:51:44.940 [main] DEBUG c.TestPrint2 - 由主线程开始唤醒a线程后,,,,开始。。。。。。。。
abcabcabcabcabc
方式3:使用park()和unpark()实现
//这两个方法的特点是它没有对象锁的概念,也没有ReentrantLock锁的概念,其他的休息室之类的都没有了
//它去停止和恢复线程的运行都是以线程自身为单位的,所以它的实现更为简单
@Slf4j(topic = "c.TestPtint3")
public class TestPrint3 {
static Thread t1;
static Thread t2;
static Thread t3;
public static void main(String[] args) {
parkUnpark parkUnpark=new parkUnpark(5);
t1= new Thread(()->{
parkUnpark.print("a",t2);
//线程t1,要打印的是a,要唤醒的是t2
});
t2= new Thread(()->{
parkUnpark.print("b",t3);
//线程t2,要打印的是b,要唤醒的是t3
});
t3= new Thread(()->{
parkUnpark.print("c",t1);
//线程t3,要打印的是c,要唤醒的是t1
});
t1.start();
t2.start();
t3.start();
//这三个线程启动后就park(暂停)住了,需要主线程来唤醒t1,让这些线程继续往下执行
LockSupport.unpark(t1);
}
}
class parkUnpark{
private int loopNumber;
//参数1:要打印的内容,参数2:要唤醒的下一个线程(需要暂停哪个,因为它是基于线程的,执行park就是暂停本线程)
public void print(String str,Thread next){
for(int i=0;
i
【控制多线程的打印顺序---交替打印(3种方式)】打印结果:abcabcabcabcabc
推荐阅读
- 放屁有这三个特征的,请注意啦!这说明你的身体毒素太多
- 爱就是希望你好好活着
- 昨夜小楼听风
- 知识
- 死结。
- 我从来不做坏事
- 烦恼和幸福
- 关于QueryWrapper|关于QueryWrapper,实现MybatisPlus多表关联查询方式
- Linux下面如何查看tomcat已经使用多少线程
- 说得清,说不清