一道面试题:面试
启动两个线程, 一个输出 1,3,5,7…99, 另外一个输出 2,4,6,8…100 最后 STDOUT 中按序输出 1,2,3,4,5…100ide
错误实现1:this
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所表示的含义不一样,咱们两个线程里面加上以下代码code
System.out.println(this.getClass());
会发现打印出对象
class pers.marscheng.thread.NotifyErrorTest$1 class pers.marscheng.thread.NotifyErrorTest$2
原来两个this不是同一个对象,匿名类会生成新的对象,因此致使两个线程获取的monitor锁是不一样的。这就致使wait()方法调用以后,两个线程都被挂起,可是再也没人能把他们唤醒,并且因为锁不一样,两个线程都同时执行了,打印出的都是1。rem
正确实现:get
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实现:it
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(); } }
拓展:io
启动三个线程, 一个输出 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作为共享变量。