Lock+Condition 相对于 wait+notify 的一个优势案例分析
问题的描述
启动3个线程打印递增的数字, 线程1先打印1,2,3,4,5, 然后是线程2打印6,7,8,9,10, 然后是线程3打印11,12,13,14,15. 接着再由线程1打印16,17,18,19,20....以此类推, 直到打印到45.
wait+notify实现:
package com.tonyluis; public class NumberPrintDemo { static int n = 1; static int state = 0; public static void main(String[] args) { new Thread(new MyThread(0)).start(); new Thread(new MyThread(1)).start(); new Thread(new MyThread(2)).start(); } } class MyThread implements Runnable{ private int state; MyThread(){ this(0); } MyThread(int state){ this.state=state; } public void run() { String threadName=Thread.currentThread().getName(); for (int i = 0; i < 3; i++) { synchronized (MyThread.class) { while (state != NumberPrintDemo.state) try { MyThread.class.wait(); } catch (InterruptedException e) { e.printStackTrace(); } for (int j = 0; j < 5; j++) System.out.println(threadName+ ": " + NumberPrintDemo.n++); System.out.println(); NumberPrintDemo.state++; NumberPrintDemo.state%=3; MyThread.class.notifyAll(); } } } }
Lock+condition实现:
package com.tonyluis; import java.util.concurrent.locks.*; public class NumberPrint { static int state = 0; static int n = 1; static Lock lock = new ReentrantLock(); static Condition condition[]=new Condition[3]; public static void main(String[] args) { for(int i=0;i<condition.length;i++) condition[i]=lock.newCondition(); NumberPrint np=new NumberPrint(); new Thread(np.new MyThread(0)).start(); new Thread(np.new MyThread(1)).start(); new Thread(np.new MyThread(2)).start(); } class MyThread implements Runnable{ private int state; MyThread(){ this(0); } MyThread(int state){ this.state=state; } public void run() { String threadName=Thread.currentThread().getName(); for (int i = 0; i < 7; i++) { //不需要放到finnally{}中释放锁,因为后面await()会释放锁 NumberPrint.lock.lock(); while (state != NumberPrint.state) try { NumberPrint.condition[state].await(); } catch (InterruptedException e) { e.printStackTrace(); } for (int j = 0; j < 5; j++) System.out.println(threadName+ ": " + NumberPrint.n++); System.out.println(); NumberPrint.state++; NumberPrint.state%=NumberPrint.condition.length; NumberPrint.condition[NumberPrint.state].signal(); try { NumberPrint.condition[state].await(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } }
使用wait+notify的实现方式,在线程0进入notifyAll()方法之后,会唤醒线程1和线程2,线程1和线程2以及线程0会展开竞争,虽然最终是由线程1获得琐,过程可能比较曲折。
使用lock+condition的实现方法,线程0只会唤醒线程1,同时进入await()方法释放锁,这样只有线程1能够执行,非常的精确,尤其是并发量比较大的情况下。