JAVA 老掉牙的面试问题 线程交替打印问题,分析实操一下
创始人
2024-05-22 00:31:45
0

前言

新的一年了,首先是祝大家新年新气象,工作顺利,生活美满 。 

万物复苏的一年, 大家都蠢蠢欲动!

金三银四快来了, 机会多不多?

‘’满大街机会‘’


好了不啰嗦,最近有比较多的小伙伴问这个线程交替打印的问题,我就来搞一搞。

正文


一个老掉牙的java面试问题 , 多线程交替打印。

有打印 ABC 的, 有打印 123 的, 有打印到100的 。

其实都一样。

ps: 最近好多小伙伴问这个,这个题这么热门么? 


实例实战思路: 

拿一个来做示例, 就交替打印ABC. (文末也说下从1到100的)



一起看看这个小题目 :

主角  


     三个线程 线程A  线程 B 线程 C

要做的事 

 交替打印  A B C

那就是 线程A 负责打印 A ,线程 B 负责打印 B ,线程C 负责打印 C  。


简单分析:


A线程打印完, B线程 打印 ;

B线程打印完 ,C 线程打印。


也就是说,这3个线程 ABC ,有顺序/协作 。

那么这三个家伙 怎么知道自己要打印东西呢?


那必然是通知 和 等待 。


思路:


三个线程都 准备就绪, 准备大展身手。


接到携带暗号的通知(默认暗号为 A) -> 核对通知的暗号 -> 打印->然后修改暗号-> 发出携带暗号通知(让别的线程认领)


如果接到通知,发现暗号不对,怎么办呢? 继续进入等待,等待下个通知的到来。 

简图:

 三个线程的一举一动 :

 

 

 

 ps: 

如果是线程A打印完,就把通知暗号改成B,并发出通知;

如果是线程B打印完,就把通知暗号改成C,并发出通知;

同样,如果是线程C打印完,就把通知改回A,继续发通知。

代码 :

写个ReentrantLock条件控制来搞一下。

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.Condition;public class DoTest {//控制三个线程 ABC,保证同一时刻只有一个线程工作private static Lock lock = new ReentrantLock(true);//  Condition ,控制等待或是 通知private static Condition conditionA = lock.newCondition();private static Condition conditionB = lock.newCondition();private static Condition conditionC = lock.newCondition();//默认的通知 暗号 Aprivate static String  CODE= "A";public static void main(String[] args) {Thread A = new Thread(() -> {while (true) {try {printA();} catch (InterruptedException e) {e.printStackTrace();}}});Thread B = new Thread(() -> {while (true) {try {printB();} catch (InterruptedException e) {e.printStackTrace();}}});Thread C = new Thread(() -> {while (true) {try {printC();} catch (InterruptedException e) {e.printStackTrace();}}});A.start();B.start();C.start();}public static void printA() throws InterruptedException {//等待lock.lock();try {//核对while (!CODE.equals("A")) {//暗号不对,就进入等待conditionA.await();}System.out.println("A");//改暗号,通知BCODE = "B";conditionB.signalAll();} finally {lock.unlock();}}public static void printB() throws InterruptedException {lock.lock();try {while (!CODE.equals("B")) {conditionB.await();}System.out.println("B");//改暗号,通知CCODE = "C";conditionC.signalAll();} finally {lock.unlock();}}public static void printC() throws InterruptedException {lock.lock();try {while (!CODE.equals("C")) {conditionC.await();}System.out.println("C");//改暗号,通知ACODE = "A";conditionA.signalAll();} finally {lock.unlock();}}}

效果:

 可以看到,三个线程 ABC 都开始 无休止的进行了 等待 -接通知 -核对- 打印-改暗号发通知 。

当然如果需要他们不这么无休止,只需要 做一个标识进行判断就好,例如 加在一起已经打印够100次了,就停止 之类的限制值。

举例, 如果交替打印,到100 就停止, 也就是 

从1~100  线程A ,线程B ,线程 B 交替打印。

ok,代码稍作调整 :

加上2个值

一个是打印的数字,这个会一直 +1 输出;

一个是用于线程循环的,之前是while(true) ,这样会一直跑。

如果 终止标记还是false,就继续执行: 

 

每个打印方法都加上判断和累计+1的代码: 

 

 看看效果:

 整体代码贴一下:
 

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.Condition;public class DoTest {//控制三个线程 ABC,保证同一时刻只有一个线程工作private static Lock lock = new ReentrantLock(true);//  Condition ,控制等待或是 通知private static Condition conditionA = lock.newCondition();private static Condition conditionB = lock.newCondition();private static Condition conditionC = lock.newCondition();//默认的通知 暗号 Aprivate static String CODE = "A";//设置初始打印值private static int COUNT_NUM = 1;//线程是否需要终止 标记private static volatile boolean IS_INTERRUPT = false;public static void main(String[] args) {Thread A = new Thread(() -> {while (!IS_INTERRUPT) {try {printA();} catch (InterruptedException e) {e.printStackTrace();}}});Thread B = new Thread(() -> {while (!IS_INTERRUPT) {try {printB();} catch (InterruptedException e) {e.printStackTrace();}}});Thread C = new Thread(() -> {while (!IS_INTERRUPT) {try {printC();} catch (InterruptedException e) {e.printStackTrace();}}});A.start();B.start();C.start();}public static void printA() throws InterruptedException {//等待lock.lock();try {if (COUNT_NUM >= 100) {IS_INTERRUPT = true;return;}//核对while (!CODE.equals("A")) {//暗号不对,就进入等待conditionA.await();}System.out.println("A, count" + COUNT_NUM);//改暗号,通知BCODE = "B";COUNT_NUM = COUNT_NUM + 1;conditionB.signalAll();} finally {lock.unlock();}}public static void printB() throws InterruptedException {lock.lock();try {if (COUNT_NUM >= 100) {IS_INTERRUPT = true;return;}while (!CODE.equals("B")) {conditionB.await();}System.out.println("B, count" + COUNT_NUM);//改暗号,通知CCODE = "C";COUNT_NUM = COUNT_NUM + 1;conditionC.signalAll();} finally {lock.unlock();}}public static void printC() throws InterruptedException {lock.lock();try {if (COUNT_NUM >= 100) {IS_INTERRUPT = true;return;}while (!CODE.equals("C")) {conditionC.await();}System.out.println("C, count" + COUNT_NUM);//改暗号,通知ACODE = "A";COUNT_NUM = COUNT_NUM + 1;conditionA.signalAll();} finally {lock.unlock();}}}

 

可能看到这里,有些初学者会心有疑惑,因为他没了解过 ReentrantLock、Lock 、Condition ,就觉得这个看了不踏实。

没事的,其实只是为了给大家实打实分析思路, 用synchronized 配合   wait() 和 notifyAll 也是一样的。

notifyAll 大不了就全部通知唤醒,然后自己核对暗号再进入等待。

示例,上代码:
 

public class DoTest1 {private volatile int COUNT_NUM = 1;private volatile String CODE = "A";private static int oneTimes = 34;private static int othersTimes = 33;void onePrint() {synchronized (this) {while(!CODE.equals("A")) {try {wait();} catch (InterruptedException e) {e.printStackTrace();}}System.out.println(Thread.currentThread().getName() + ": " + COUNT_NUM);COUNT_NUM++;CODE = "B";notifyAll();}}void twoPrint() {synchronized (this) {while(!CODE.equals("B")) {try {wait();} catch (InterruptedException e) {e.printStackTrace();}}System.out.println(Thread.currentThread().getName() + ": " + COUNT_NUM);COUNT_NUM++;CODE = "C";notifyAll();}}void threePrint() {synchronized (this) {while(!CODE.equals("C")) {try {wait();} catch (InterruptedException e) {e.printStackTrace();}}System.out.println(Thread.currentThread().getName() + ": " + COUNT_NUM);COUNT_NUM++;CODE = "A";notifyAll();}}public static void main(String[] args) {DoTest1 printNumber = new DoTest1();new Thread(() -> {for (int i = 0; i < oneTimes; i++) {printNumber.onePrint();}},"线程A").start();new Thread(() -> {for (int i = 0; i < othersTimes; i++) {printNumber.twoPrint();}},"线程B").start();new Thread(() -> {for (int i = 0; i < othersTimes; i++) {printNumber.threePrint();}},"线程C").start();}
}

代码简析:

 看看效果:

 

好了,该篇就到这吧。

相关内容

热门资讯

80岁生日宴会致辞 80岁生日宴会致辞(精选11篇)  在学习、工作或生活中,大家都不可避免地会接触到致辞吧,致辞具有有...
婚宴长辈证婚人致辞 婚宴长辈证婚人致辞  在平日的学习、工作和生活里,大家总少不了要接触或使用致辞吧,致辞受场合、事件的...
元旦舞会主持词 元旦舞会主持词(精选7篇)  主持词要尽量增加文化内涵、寓教于乐,不断提高观众的文化知识和素养。在人...
圣诞联欢会主持词 圣诞联欢会主持词  活动对象的不同,主持词的写作风格也会大不一样。时代不断在进步,主持成为很多活动不...
美好童年—庆“六一”大型活动... 美好童年—庆“六一”大型活动主持词  利用在中国拥有几千年文化的诗词能够有效提高主持词的感染力。随着...
毕业晚会主持词串词 毕业晚会主持词串词  毕业,是人生的一个转折点,愿你们能展开双翼,飞得更高、看得更远。下面是小编给大...
运动会致辞 运动会致辞(精选5篇)  无论在学习、工作或是生活中,大家或多或少都用到过致辞吧,致辞要求风格的雅、...
六一儿童节的主持稿 六一儿童节的主持稿(精选8篇)  随着社会一步步向前发展,我们都不可避免地要接触到主持稿,主持稿是主...
元旦文艺汇演主持稿 元旦文艺汇演主持稿范文(通用5篇)  在当下社会,很多情况下我们需要用到主持稿,主持稿起到承上启下的...
颁奖主持词 颁奖主持词三篇  主持人在一场活动中是十分重要的,一个好的主持人是一直带动着活动过程中的气氛,让大家...
婚宴答谢宴简短主持词 婚宴答谢宴简短主持词  主持词要根据活动对象的不同去设置不同的主持词。在人们积极参与各种活动的今天,...
汽车公司庆典主持词 汽车公司庆典主持词  利用在中国拥有几千年文化的诗词能够有效提高主持词的感染力。现今社会在不断向前发...
古筝音乐会主持词 古筝音乐会主持词6篇  主持词要把握好吸引观众、导入主题、创设情境等环节以吸引观众。在一步步向前发展...
小学元旦联欢会主持词开场白和... 小学元旦联欢会主持词开场白和结束词  根据活动对象的不同,需要设置不同的主持词。随着社会一步步向前发...
知识竞赛主持词 知识竞赛主持词(精选6篇)  主持词的写作需要将主题贯穿于所有节目之中。在人们越来越多的参与各种活动...
小学家长会学生欢迎词 小学家长会学生欢迎词小学家长会学生欢迎词文章标题:小学家长会学生欢迎词家长会欢迎辞亲爱的叔叔阿姨,爷...
消夏晚会主持词 2017消夏晚会主持词  漫漫暑假,天气越来越燥热,不妨在炎热的午后,参加一场纳凉晚会,欣赏社区带来...
周立波脱口秀台词 周立波脱口秀台词集锦四十岁之前喝酒是为了别人的一句~~厉害!醉了!!四十岁以后喝酒是为了自己的一句~...
圣诞节活动主持词节目串词 圣诞节活动主持词节目串词3篇  根据活动对象的不同,需要设置不同的主持词。在人们积极参与各种活动的今...
生日华诞主持词 生日华诞主持词范文各位领导,各位朋友,各位来宾,女士们,先生们:  中午好。  今天是个喜庆的日子,...