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();}
}

代码简析:

 看看效果:

 

好了,该篇就到这吧。

相关内容

热门资讯

高考语文作文写作大全范文24... 高考语文作文写作大全范文24篇 篇一:《青春之梦》青春是一段美好而又短暂的时光,它是我们追逐梦想的时...
2021年全国新高考Ⅰ卷高考... 2021年全国新高考Ⅰ卷高考优秀作文 篇一标题:探索创新:培养学生的实践能力随着社会的不断发展和进步...
高考热点素材:网络暴力(精彩... 高考热点素材:网络暴力 篇一网络暴力是一种通过网络平台进行的攻击、侮辱、威胁等恶意行为。随着互联网的...
高考作文有哪些素材(实用6篇... 高考作文有哪些素材 篇一高考作文是每个考生都要面对的一项任务,其中素材的选择对于作文的质量至关重要。...
2006年全国卷Ⅰ高考满分作... 篇一:追求中的自我价值在追求中认清自我价值,这是一个让人深思的命题。在我看来,追求不仅是一种行动,更...
高考家长寄语(经典6篇) 高考家长寄语 篇一高考是每个学生和家长都非常重视的一场考试,对于学生来说,这是他们为自己的未来奠定基...
网络暴力的高考写作素材(精选... 网络暴力的高考写作素材 篇一网络暴力是指在网络空间中,个别人或群体针对特定对象进行侮辱、恐吓、谩骂等...
作文素材大全(推荐3篇) 作文素材大全 篇一第一篇内容:环境保护环境保护是当今社会亟待解决的一个重要问题。随着工业化的快速发展...
直面高考:何其沉重的关怀【优... 直面高考:何其沉重的关怀 篇一高考是每一个中国学生都无法逃避的一场考试,它承载着家庭和社会的期望,也...
2021年北京卷高考优秀作文... 2021年北京卷高考优秀作文:论生逢其时 篇一生逢其时——青春的无限可能时光荏苒,岁月如梭。站在20...
奔跑追梦高考作文【优秀6篇】 奔跑追梦高考作文 篇一高考,是每个学生追逐梦想的起跑线,也是一次对自己的综合能力的全面检验。对于我来...
我的作文800字(精简3篇) 我的作文800字 篇一:如何保护环境随着现代工业化和城市化的快速发展,环境问题日益严重。我们每个人都...
高考时评类作文范文最新(优质... 高考时评类作文范文最新 篇一高考改革:激发学生学习兴趣的关键高考是中国教育体系中最重要的考试,对于学...
高考话题作文:假如记忆可以移... 高考话题作文:假如记忆可以移植_话题作文 篇一假如记忆可以移植记忆是人类大脑的重要组成部分,它记录了...
高考优秀作文范文24篇(推荐... 高考优秀作文范文24篇 篇一:探索未知的世界在这个信息爆炸的时代,我们对于未知世界的探索变得更加迫切...
河南高考高分作文(精简6篇) 河南高考高分作文 篇一:探索未知的勇气作文题目:探索未知的勇气河南高考高分作文 篇一勇气是一种挑战自...
优秀学子高考经验分享范文【优... 优秀学子高考经验分享范文 篇一高考是每个学生都要面对的重要考试,对于很多人来说,高考是决定未来的关键...
高中易混淆词语解析(最新5篇... 高中易混淆词语解析 篇一在高中阶段,学生们经常会遇到一些易混淆的词语,尤其是在语文和英语学习中。这些...
高考语文常见易读错的词语(经... 高考语文常见易读错的词语 篇一在高考语文考试中,常常会出现一些易读错的词语,这些词语看似简单,却经常...
高考满分作文【推荐6篇】 高考满分作文 篇一:努力与坚持的力量高考是人生中的一次重要考试,它不仅仅是对学生知识的考验,更是对学...