关键字synchronized与wait()和notify()/notifyAll()方法相结合可以实现等待/通知模式。
类ReentrantLock同样可以实现该功能,但是要借助于Condition对象。它具有更好的灵活性,比如可以实现多路通知功能,也就是在一个Lock对象里面可以创建多个Condition(对象监视器)实例,线程对象可以注册在指定Condition中,从而有选择性的进行线程通知,在调度线程上更加灵活
使用notify和notifyAll方法进行通知时,被通知的线程是由JVM随机选择的,但是ReentrantLock结合Condition可以实现前面介绍过的“选择性通知”,这个功能是非常重要的。
synchronized相当于整个Lock对象中只有单一的Condition对象,所有线程都注册在它一个对象上,线程开始notifyAll()时,需要通知所有waiting的线程,没有选择权,会出现相当大的效率问题
简单例子:
public class TestLock implements Runnable { public static ReentrantLock lock = new ReentrantLock(); @Override public void run() { try { lock.lock(); for (int i = 0; i < 5; i++) { System.out.println(i); Thread.sleep(100); } } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } public static void main(String[] args) { TestLock lock = new TestLock(); new Thread(lock).start(); new Thread(lock).start(); new Thread(lock).start(); } }
得到结果是顺序打印。
condition调用await()方法后,会释放lock,接收到同一个condition的signal后线程需要重新获得锁,
使用Condition例子:
public class TestLock { public static ReentrantLock lock = new ReentrantLock(); public static Condition newCondition = lock.newCondition(); public static void main(String[] args) { class MyRunnable1 implements Runnable { @Override public void run() { try { lock.lock(); System.out.println("myRunnable1:await:begin"); newCondition.await(); System.out.println("myRunnable1:await:end"); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } } ; class MyRunnable2 implements Runnable { @Override public void run() { try { lock.lock(); System.out.println("myRunnable2:signal:begin"); newCondition.signal(); System.out.println("myRunnable2:signal:end"); } finally { lock.unlock(); } } } new Thread(new MyRunnable1()).start(); new Thread(new MyRunnable2()).start(); } }
结果: