实现思路
本质上这一题是考察对于线程等待同步机制的掌握
核心思路是:
- 两个线程(分别称其为打印奇数和偶数的线程)共同持有一个锁,这个锁是用来打印的,只有获取到这个锁才能进行打印。
- 打印奇数和偶数的线程分别先判断共享变量是奇数还是偶数
- 如果是符合自己当前要求的数,就打印,打印完唤醒另一个等待的线程
- 如果不是自己当前要求的数,就释放锁,给另一个线程打印
synchronized + wait/notify
基于JVM级别自动获取和释放锁的 synchronized + Object.wait()/Object.notify()
我们有了如下的实现
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
| public class MultiThreadPrint {
public static volatile int num = 0;
public static final Object PRINT_LOCK = new Object();
public static final int MAX_NUM = 100;
public static void main(String[] args) {
Thread odd = new Thread(() -> printNum(false), "odd thread"); Thread even = new Thread(() -> printNum(true), "even thread");
even.start(); odd.start(); }
private static void printNum(boolean isEven) { while (true) { synchronized (PRINT_LOCK) { if (num > MAX_NUM) { PRINT_LOCK.notify(); return; } boolean condition = isEven ? num % 2 == 0 : num % 2 == 1; if (condition) { System.out.println(Thread.currentThread().getName() + ":num=" + num++); PRINT_LOCK.notify(); } else { try { PRINT_LOCK.wait(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); return; } } } } } }
|
ReentrantLock + Condition
ReentrantLock 可以看作是 synchronized 的升级版,支持的功能更多。配合 Condition 使用可以实现类似 synchronized + wait/notify 的效果
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
| public class MultiThreadPrintReentrantLock {
private static int num = 0;
private static final int MAX_COUNT = 100;
private static final ReentrantLock LOCK = new ReentrantLock();
private static final Condition ODD_PRINT = LOCK.newCondition();
private static final Condition EVEN_PRINT = LOCK.newCondition();
public static void main(String[] args) { Thread evenThread = new Thread(() -> printNum(true), "evenThread"); Thread oddThread = new Thread(() -> printNum(false), "oddThread"); evenThread.start(); oddThread.start(); }
private static void printNum(boolean isEven) { Condition signalCondition = isEven ? ODD_PRINT : EVEN_PRINT; Condition awaitCondition = isEven ? EVEN_PRINT : ODD_PRINT; while (true) { LOCK.lock(); try { if (num > MAX_COUNT) { ODD_PRINT.signal(); EVEN_PRINT.signal(); return; } boolean print = isEven ? num % 2 == 0 : num % 2 == 1; if (print) { System.out.println(Thread.currentThread().getName() + ":num=" + num); num++; signalCondition.signal(); } else { try { awaitCondition.await(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); return; } } } finally { LOCK.unlock(); } } } }
|