Condition
实例实质上被绑定到一个锁上。要为特定 Lock
实例获得 Condition
实例,使用其 newCondition()
方法。
Condition
将 Object
监视器方法(wait
、notify
和 notifyAll
)分解成截然不同的对象,以便通过将这些对象与任意 Lock
实现组合使用,为每个对象提供多个等待 set(wait-set)。其中,Lock
替代了 synchronized
方法和语句的使用,Condition
替代了 Object 监视器方法的使用。
下面使用condition的await和singal方法可以替代object的wait和notify方法,lock锁替代了synchronized方法块,实例代码如下:
public void init() { Business business = new Business(); // 子线程 new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < 50; i++) {business.sub(i);} } }).start(); // 主线程 for (int j = 0; j < 50; j++) {business.main(j);} } class Business { boolean isSub = true; public void main(int n) { Lock lock = new ReentrantLock(); Condition condition = lock.newCondition(); lock.lock(); try { if (isSub) {condition.await();} for (int i = 0; i < 7; i++) { System.out.println("main ----" + Thread.currentThread().getName() + ",第" + n + "次运行,当前循环了" + i + "次"); } System.out.println(); isSub = true; condition.signal(); } catch (Exception e) { lock.unlock(); } } public void sub(int n) { Lock lock = new ReentrantLock(); Condition condition = lock.newCondition(); lock.lock(); try { if (!isSub) {condition.await();} for (int i = 0; i < 13; i++) { System.out.println("sub ----" + Thread.currentThread().getName() + ",第" + n + "次运行,当前循环了" + i + "次"); } System.out.println(); isSub = false; condition.signal(); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } }
condition不仅可以替代object的wait和notify方法,可以实现多路复用的功能,废话少说先上代码:
final Lock lock = new ReentrantLock(); final Condition notFull = lock.newCondition(); final Condition notEmpty = lock.newCondition(); final Object[] items = new Object[100]; int putptr, takeptr, count; public void put(Object x) throws InterruptedException { lock.lock(); try { while (count == items.length) notFull.await(); items[putptr] = x; if (++putptr == items.length) putptr = 0; ++count; notEmpty.signal(); } finally { lock.unlock(); } } public Object take() throws InterruptedException { lock.lock(); try { while (count == 0) notEmpty.await(); Object x = items[takeptr]; if (++takeptr == items.length) takeptr = 0; --count; notFull.signal(); return x; } finally { lock.unlock(); } }
作为一个示例,假定有一个绑定的缓冲区,它支持 put
和 take
方法。如果试图在空的缓冲区上执行 take
操作,则在某一个项变得可用之前,线程将一直阻塞;如果试图在满的缓冲区上执行 put
操作,则在有空间变得可用之前,线程将一直阻塞。我们喜欢在单独的等待 set 中保存 put
线程和 take
线程,这样就可以在缓冲区中的项或空间变得可用时利用最佳规划,一次只通知一个线程。可以使用两个 Condition
实例来做到这一点。
注意,Condition
实例只是一些普通的对象,它们自身可以用作 synchronized
语句中的目标,并且可以调用自己的 wait
和 notification
监视器方法。获取 Condition
实例的监视器锁或者使用其监视器方法,与获取和该 Condition
相关的 Lock
或使用其 waiting
和 signalling
方法没有什么特定的关系。为了避免混淆,建议除了在其自身的实现中之外,切勿以这种方式使用 Condition
实例。
除非另行说明,否则为任何参数传递 null
值将导致抛出 NullPointerException
。
此外,提供一个第一个实例代码的升级,让三个线程有序的各执行20次。
public void init() { Business business = new Business(); // 子线程 new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < 20; i++) {business.sub(i);} } }).start(); // 次子线程 new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < 20; i++) {business.subSub(i);} } }).start(); // 主线程 for (int j = 0; j < 20; j++) {business.main(j);} } class Business { int flag=0; Lock lock = new ReentrantLock(); Condition condition0 = lock.newCondition(); Condition condition1 = lock.newCondition(); Condition condition2 = lock.newCondition(); public void main(int n) { lock.lock(); try { if (flag!=0) {condition0.await();} for (int i = 0; i < 7; i++) { System.out.println("main ----" + Thread.currentThread().getName() + ",第" + n + "次运行,当前循环了" + i + "次"); } System.out.println(); flag=1; condition1.signal(); } catch (Exception e) { lock.unlock(); } } public void sub(int n) { lock.lock(); try { if (flag!=1) {condition1.await();}// for (int i = 0; i < 13; i++) { System.out.println("sub ----" + Thread.currentThread().getName() + ",第" + n + "次运行,当前循环了" + i + "次"); } System.out.println(); flag = 2; condition2.signal(); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } public void subSub(int n) { lock.lock(); try { if (flag!=2) {condition2.await();}// for (int i = 0; i < 23; i++) { System.out.println("sub--Sub ----" + Thread.currentThread().getName() + ",第" + n + "次运行,当前循环了" + i + "次"); } System.out.println(); flag = 0; condition0.signal(); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } } public static void main(String[] args) { new ThreeLockContidion2().init(); }