wait-notify模型面试题

mac2022-06-30  23

一道面试题:

启动两个线程, 一个输出 1,3,5,7…99, 另一个输出 2,4,6,8…100 最后 STDOUT 中按序输出 1,2,3,4,5…100

错误实现1:

public class NotifyErrorTest { private int i = 1; Thread t1 = new Thread(){ @Override public void run() { while (true) { synchronized (this) { notify(); if (i <= 100) { System.out.println(currentThread().getName() + ":" + i); i++; try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } } } }; Thread t2 = new Thread(){ @Override public void run() { while (true) { synchronized (this) { notify(); if (i <= 100) { System.out.println(currentThread().getName() + ":" + i); i++; try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } } } }; public static void main(String[] args){ NotifyErrorTest test = new NotifyErrorTest(); test.t1.start(); test.t2.start(); } }

结果:

Thread-0:1 Thread-1:1

打印出这两个后,线程就一直被挂起了。为什么会这样呢。 先不考虑这种难看的重复代码需不需要重构,本身代码就有问题,虽然看起来都用了this,但是其实两个this所表示的含义不同,我们两个线程里面加上如下代码

System.out.println(this.getClass());

会发现打印出

class pers.marscheng.thread.NotifyErrorTest$1 class pers.marscheng.thread.NotifyErrorTest$2

原来两个this不是同一个对象,匿名类会生成新的对象,所以导致两个线程获取的monitor锁是不同的。这就导致wait()方法调用之后,两个线程都被挂起,但是再也没人能把他们唤醒,而且由于锁不同,两个线程都同时执行了,打印出的都是1。

正确实现:

public class NotifyTest implements Runnable { int i = 1; public static void main(String[] args) { NotifyTest test = new NotifyTest(); Thread t1 = new Thread(test); Thread t2 = new Thread(test); t1.start(); t2.start(); } @Override public void run() { while (true) { synchronized (this) { this.notify(); if (i <= 100) { String threadName = Thread.currentThread().getName(); System.out.println(threadName + ":" + i); i++; try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } } } }

通过condition实现:

public class ConditionTest implements Runnable{ Lock lock = new ReentrantLock(); Condition condition = lock.newCondition(); int i = 1; @Override public void run() { try { lock.lock(); while (true) { condition.signal(); if (i <= 100) { System.out.println(Thread.currentThread().getName() + ":" + i); i++; try { condition.await(); } catch (InterruptedException e) { e.printStackTrace(); } } } } finally { lock.unlock(); } } public static void main(String[] args) { ConditionTest test = new ConditionTest(); Thread t1 = new Thread(test); Thread t2 = new Thread(test); t1.start(); t2.start(); } }

拓展:

启动三个线程, 一个输出 1,4,7,10…100, 一个输出 2,5,8,11…101,最后一个暑促3,6,9,12...102 最后 STDOUT 中按序输出 1,2,3,4,5…102

实现:

public class NotifyTest2 implements Runnable { private Object prev; private Object self; AtomicInteger i; private NotifyTest2(AtomicInteger num,Object prev, Object self) { this.i = num; this.prev = prev; this.self = self; } @Override public void run() { while (true) { synchronized (prev) { synchronized (self) { if (i.get() <= 102) { System.out.println(Thread.currentThread().getName() + ":" + i.get()); i.getAndIncrement(); self.notify(); } } try { prev.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } } public static void main(String[] args) { Object a = new Object(); Object b = new Object(); Object c = new Object(); AtomicInteger num = new AtomicInteger(1); NotifyTest2 testA = new NotifyTest2(num,c,a); NotifyTest2 testB = new NotifyTest2(num,a,b); NotifyTest2 testC = new NotifyTest2(num,b,c); new Thread(testA).start(); new Thread(testB).start(); new Thread(testC).start(); } }

利用AtomicInteger做为共享变量。

转载于:https://www.cnblogs.com/MarsCheng/p/10355945.html

最新回复(0)