• Java两个线程使用最基础wait/notify轮流打印数字和字符


    背景:

    最基础的java线程协同工作题目,也是笔试常见题目。 题目要求两个线程轮流打印数字(1-26)和字符(a到z)。

    代码

    class PrintNumRunnable implements Runnable {
      final Object object;
      final static int MAX_LOOP = 26;
      public PrintNumRunnable(Object object) {
        this.object = object;
      }
    
      @Override
      public void run() {
        int count = 0;
    
        while (count++ < MAX_LOOP) {
          synchronized (object) {
            try {
              object.wait();
            } catch (InterruptedException e) {
              e.printStackTrace();
            }
    
            System.out.print(count);
            object.notify();
          }
    
        }// end of while
    
      }
    }
    
    class PrintCharRunnable implements Runnable {
      final Object object;
      final static char MAX_CHAR = 'z';
    
      public PrintCharRunnable(Object object) {
        this.object = object;
      }
      @Override
      public void run() {
    
        for(char count = 'a'; count <= MAX_CHAR; count++) {
          synchronized (object) {
            System.out.print(count);
            object.notify();
            try {
              object.wait();
            } catch (InterruptedException e) {
              e.printStackTrace();
            }
          }
        }// end of while
    
      }
    }
    
    public class TwoThreadAlternatelyPrintDemo
    {
      public static void main(String[] args) throws InterruptedException {
        System.out.println("main thread start ...");
    
        Object threadSyncObj  = new Object();
    
        PrintNumRunnable printNum = new PrintNumRunnable(threadSyncObj);
        PrintCharRunnable printChar = new PrintCharRunnable(threadSyncObj);
        Thread numThread = new Thread(printNum);
        Thread charThread = new Thread(printChar);
    
        // 启动顺便不能变,先numThread,后charThread
        numThread.start();
        charThread.start();
    
        // wait to finish
        numThread.join();
        charThread.join();
    
        System.out.println("\nmain thread end");
      }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77

    解释

    numThread先启动,进入wait阻塞状态
    charThread启动后,打印一个字符,然后通知numThread,自己就wait
    numThread得到通知后打印数字,通知charThread, 自己进入循环的下一个迭代,并重新wait
    charThread收到通知,打印一个字符,然后通知numThread,自己就wait

    依次循环最后,当字符到z的时候, charThread进入wait
    当数字打印26后,发送notify,自己退出线程。 charThread收到notify后也退出线程。主线程的join就结束了

    代码中特意提到了不能改变两个thread的启动顺序。这是因为charThread.start();先启动了,打印了a,然后他就notify后,立刻进入wait阻塞状态了,此时numThread线程可能还未启动,没有进入到wait,当numThread正式启动后,进入wait时已经错过了charThread之前对它发送的notify消息了,此时两个线程都进入了wait状态。 可以想想是不是可以增加其他flag避免此类状况

    后记

    其实可以使用多种方式实现该打印题目,比如阻塞队列,打印数字的想成打印后,需要向阻塞队列put, 打印字符的线程从阻塞队列take。 阻塞队列只能容量1个元素。 这里不在展示

    BlockingDeque<String> blockingDeque = (BlockingDeque) new ArrayBlockingQueue(1);
    
    • 1

    或者使用LockSupport, 相比之下wait和notify、 阻塞队列都是比较常用,能快速想起来的方式

  • 相关阅读:
    图扑 Web SCADA 零代码组态水泥生产工艺流程 HMI
    项目示例 - 4.配置中心 - 1.Nacos
    北大联合智源提出训练框架LLaMA-Rider
    【BUUCTF】roarctf_2019_realloc_magic---从一道题认识realloc函数+stdout泄露libc地址实战
    elasticsearch查询bool和多字段查询
    智能井盖:把好城市地下“安全门”
    redis-cli报错Could not connect to Redis at 127.0.0.1:6379: Connection refused
    Redis灵魂拷问,你扛得住几道?
    QT-如何将字符串转成唯一整型ID
    【opencv-python】 视频转图片代码
  • 原文地址:https://blog.csdn.net/russle/article/details/133827611