跳至主要內容

JUC 八股24 (实际场景)

codejavajuc八股约 482 字大约 2 分钟

实际场景

多线程打印奇偶数,怎么控制打印的顺序

使用 ReentrantLock + Condition

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class OddEvenPrinterLock {
  private int count = 1;
  private final int MAX = 10;
  
  // 主线程创建的锁对象
  private final ReentrantLock lock = new ReentrantLock(); 
  // 创建两个条件变量,相当于两个休息室
  private final Condition oddCondition = lock.newCondition();
  private final Condition evenCondition = lock.newCondition();

  public void printOdd() {
      while (count <= MAX) {
          lock.lock(); // 尝试获取锁
          try {
              while (count % 2 == 0) {
                oddCondition.await(); // 奇数线程去奇数休息室睡觉,并释放锁
              }
              if (count <= MAX) {
                System.out.println(Thread.currentThread().getName() + " 打印奇数: " + count);
                count++;
                evenCondition.signal(); // 明确去偶数休息室叫醒偶数线程
              }
          } catch (InterruptedException e) {
              Thread.currentThread().interrupt();
          } finally {
              lock.unlock(); // 切记在 finally 中释放锁
          }
      }
  }

  public void printEven() {
      while (count <= MAX) {
          lock.lock();
          try {
              while (count % 2 != 0) {
                  evenCondition.await(); // 偶数线程去偶数休息室睡觉,并释放锁
              }
              if (count <= MAX) {
                  System.out.println(Thread.currentThread().getName() + " 打印偶数: " + count);
                  count++;
                  oddCondition.signal(); // 明确去奇数休息室叫醒奇数线程
              }
          } catch (InterruptedException e) {
              Thread.currentThread().interrupt();
          } finally {
              lock.unlock();
          }
      }
  }

  public static void main(String[] args) {
      OddEvenPrinterLock printer = new OddEvenPrinterLock();
      new Thread(printer::printOdd, "Thread-Odd").start();
      new Thread(printer::printEven, "Thread-Even").start();
  }
}

使用 synchronized + wait/notify

public class OddEvenPrinterSync {
  private int count = 1;
  private final int MAX = 10;
  private final Object lock = new Object(); // 共享的锁对象

  public void printOdd() {
      while (count <= MAX) {
          synchronized (lock) {
              // 如果当前是偶数,奇数线程就主动挂起等待
              while (count % 2 == 0) {
                  try {
                      lock.wait(); // 释放锁,进入阻塞状态,等待被唤醒
                  } catch (InterruptedException e) {
                      Thread.currentThread().interrupt();
                  }
              }
              if (count <= MAX) {
                  System.out.println(Thread.currentThread().getName() + " 打印奇数: " + count);
                  count++;
                  lock.notify(); // 活干完了,叫醒挂在 lock 上的其他线程(偶数线程)
              }
          }
      }
  }

  public void printEven() {
      while (count <= MAX) {
          synchronized (lock) {
              // 如果当前是奇数,偶数线程就主动挂起等待
              while (count % 2 != 0) {
                  try {
                      lock.wait(); 
                  } catch (InterruptedException e) {
                      Thread.currentThread().interrupt();
                  }
              }
              if (count <= MAX) {
                  System.out.println(Thread.currentThread().getName() + " 打印偶数: " + count);
                  count++;
                  lock.notify(); // 活干完了,叫醒奇数线程
              }
          }
      }
  }

  public static void main(String[] args) {
      OddEvenPrinterSync printer = new OddEvenPrinterSync();
      new Thread(printer::printOdd, "Thread-Odd").start();
      new Thread(printer::printEven, "Thread-Even").start();
  }
}
上次编辑于: