控制多线程的打印顺序---交替打印(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

    推荐阅读