ToB企服应用市场:ToB评测及商务社交产业平台

标题: 三个线程交替打印ABC100次问题思考 [打印本页]

作者: 卖不甜枣    时间: 2022-9-16 17:21
标题: 三个线程交替打印ABC100次问题思考
如题:使用三个线程交替打印ABC,直至100次代码实战

方法一:

使用notify()、wait()方法
  1. public class PrintAbc {
  2.     /**
  3.      * 唤醒线程的状态值 state: threadA = 0, threadB = 1, threadC =2,
  4.      */
  5.     int state = 0;
  6.     /**
  7.      * 循环技术,初始值0
  8.      */
  9.     int count = 0;
  10.     public void print(PrintAbc printAbc) {
  11.         Thread threadA = new Thread(() -> {
  12.             extracted(printAbc, "A", 0, 1);
  13.         });
  14.         Thread threadB = new Thread(() -> {
  15.             extracted(printAbc, "B", 1, 2);
  16.         });
  17.         Thread threadC = new Thread(() -> {
  18.             extracted(printAbc, "C", 2, 0);
  19.         });
  20.         threadC.start();
  21.         threadB.start();
  22.         try {
  23.             Thread.sleep(1000L);
  24.         } catch (InterruptedException e) {
  25.             throw new RuntimeException(e);
  26.         }
  27.         threadA.start();
  28.     }
  29.     /**
  30.      * 交替打印abc,直至100次
  31.      *
  32.      * @param printAbc  锁对象
  33.      * @param a         打印的字母, 对应A、B、C
  34.      * @param needState 当前线程对应的state状态值
  35.      * @param nextState 唤醒下一个线程所需state状态值
  36.      */
  37.     private void extracted(PrintAbc printAbc, String a, int needState, int nextState) {
  38.         while (true) {
  39.             synchronized (printAbc) {
  40.                 if (count >= 100) {
  41.                     break;
  42.                 }
  43.                 if (printAbc.count < 100 && printAbc.state == needState) {
  44.                     System.out.println(a);
  45.                     printAbc.state = nextState;
  46.                     printAbc.count++;
  47.                     printAbc.notifyAll();
  48.                 } else {
  49.                     try {
  50.                         printAbc.wait();
  51.                     } catch (InterruptedException e) {
  52.                         throw new RuntimeException(e);
  53.                     }
  54.                 }
  55.             }
  56.         }
  57.     }
  58.     public static void main(String[] args) {
  59.         PrintAbc printAbc = new PrintAbc();
  60.         printAbc.print(printAbc);
  61.     }
  62. }
复制代码
上述代码使用notify(),wait(),进行线程间的条件唤醒,state的初始状态是0,对应线程A,所以第一次打印字母也一定是A
方法二

使用ReentrantLock的的Condition条件
  1. public class PrintAbcByCondition {
  2.     /**
  3.      * 循环计数初始值0
  4.      */
  5.     static int count = 0;
  6.     public void print() {
  7.         ReentrantLock reentrantLock = new ReentrantLock();
  8.         Condition conditionA = reentrantLock.newCondition();
  9.         Condition conditionB = reentrantLock.newCondition();
  10.         Condition conditionC = reentrantLock.newCondition();
  11.         Thread threadA = new Thread(() -> {
  12.             while (true) {
  13.                 try {
  14.                     reentrantLock.lock();
  15.                     // threadA进来打印A然后唤醒threadB
  16.                     if (count < 100) {
  17.                         System.out.println("A");
  18.                         count++;
  19.                         conditionB.signal();
  20.                     }
  21.                     conditionA.await();
  22.                 } catch (InterruptedException e) {
  23.                     throw new RuntimeException(e);
  24.                 } finally {
  25.                     reentrantLock.unlock();
  26.                 }
  27.             }
  28.         });
  29.         Thread threadB = new Thread(() -> {
  30.             while (true) {
  31.                 try {
  32.                     reentrantLock.lock();
  33.                     // threadB进来就阻塞等待threadA使用完毕
  34.                     conditionB.await();
  35.                     if (count < 100) {
  36.                         System.out.println("B");
  37.                         count++;
  38.                         conditionC.signal();
  39.                     }
  40.                 } catch (InterruptedException e) {
  41.                     throw new RuntimeException(e);
  42.                 } finally {
  43.                     reentrantLock.unlock();
  44.                 }
  45.             }
  46.         });
  47.         Thread threadC = new Thread(() -> {
  48.             while (true) {
  49.                 try {
  50.                     reentrantLock.lock();
  51.                     // threadC进来就阻塞等待threadB使用完毕
  52.                     conditionC.await();
  53.                     if (count < 100) {
  54.                         System.out.println("C");
  55.                         count++;
  56.                         conditionA.signal();
  57.                     }
  58.                 } catch (InterruptedException e) {
  59.                     throw new RuntimeException(e);
  60.                 } finally {
  61.                     reentrantLock.unlock();
  62.                 }
  63.             }
  64.         });
  65.         threadC.start();
  66.         threadB.start();
  67.         try {
  68.             Thread.sleep(1000L);
  69.         } catch (InterruptedException e) {
  70.             throw new RuntimeException(e);
  71.         }
  72.         threadA.start();
  73.     }
  74.     public static void main(String[] args) {
  75.         new PrintAbcByCondition().print();
  76.     }
  77. }
复制代码
使用ReentrantLock的的Condition条件,很容易能实现三个线程之间的交替打印,需要注意的一点就是线程A是需要第一个执行,可以看到代码里threadA在等待1秒后在执行,也能确保是第一个进行打印,原因如下:
线程B和线程C中任意一个线程拿到锁都需要等待条件成立,线程C依赖线程B,而线程B依赖线程A,所以他们会一直阻塞直至线程A执行
上述两个方法中,核心问题就是如何实现线程间的条件唤醒,如方法一,我们可以自定义state状态变量来与各个线程绑定,每个线程都有自己对应的state状态,当state变量当前值与线程自身期望的state值相同才唤醒当前线程。也可以使用juc中ReentrantLock的提供的Condition条件完成线程间的条件唤醒
至此,三个线程交替打印ABC100次的实现方法介绍完毕

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4