在之前的Java并发(一)wait()与notifyAll()一文中的例子中,我们使用了wait()和notifyAll()来模拟了给汽车打蜡和抛光的情景。在JavaSE5中,还提供了java.util.concurrent.locks.Condition对象供我们使用。你可以在Condition上调用await()来挂起一个任务。当外部条件发生变化,意味着某个任务应该继续执行时,你可以通过调用signal()来通知这个任务,或者调用signalAll()来唤醒所有在这个Condition上被其自身挂起的任务(与使用signal()相比,signalAll()是更安全的方式)。
下面是WaxOnMatic.java的重写版本,它包含了一个Condition,用来在waitForWaxing()或waitForBuffing()内部挂起一个任务:
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; class Car { private Lock lock = new ReentrantLock(); private Condition condition = lock.newCondition(); private boolean waxOn = false;//是否上蜡 //上蜡 public void waxed() { lock.lock(); try { waxOn = true; condition.signalAll(); } finally { lock.unlock(); } } //抛光 public void buffed() { lock.lock(); try { waxOn = false; condition.signalAll(); } finally { lock.unlock(); } } //等待上蜡 public void waitForWaxing() throws InterruptedException { lock.lock(); try { while(waxOn == false) { condition.await(); } } finally { lock.unlock(); } } //等待抛光 public void waitForBuffing() throws InterruptedException { lock.lock(); try { while(waxOn == true) { condition.await(); } } finally { lock.unlock(); } } } class WaxOnTask implements Runnable { private Car car; private String name; public WaxOnTask(String name, Car car) { this.name = name; this.car = car; } @Override public void run() { try { while(!Thread.interrupted()) { System.out.println("[" + name + "] is Wax on!");//正在上蜡 TimeUnit.MILLISECONDS.sleep(300); car.waxed();//上蜡完成 car.waitForBuffing();//等待抛光 } } catch (InterruptedException e) { System.out.println("[" + name + "] Exiting WaxOnTask via interrupt."); } } } class BuffTask implements Runnable { private Car car; private String name; public BuffTask(String name, Car car) { this.name = name; this.car = car; } @Override public void run() { try { while(!Thread.interrupted()) { car.waitForWaxing();//等待上蜡 System.out.println("[" + name + "] Buffing...");//正在抛光 TimeUnit.MILLISECONDS.sleep(300); car.buffed();//抛光完成 } } catch (InterruptedException e) { System.out.println("[" + name + "] Exiting BuffTask via interrupt."); } } } public class WaxOMatic2 { public static void main(String[] args) throws Exception { Car car = new Car(); ExecutorService exec = Executors.newCachedThreadPool(); //上蜡 exec.execute(new WaxOnTask("Waxx", car)); //抛光 exec.execute(new BuffTask("Buff", car)); //运行一段时间,停止ExecutorService TimeUnit.SECONDS.sleep(3); exec.shutdownNow(); } }
执行结果:
[Waxx] is Wax on! [Buff] Buffing... [Waxx] is Wax on! [Buff] Buffing... [Waxx] is Wax on! [Buff] Buffing... [Waxx] is Wax on! [Buff] Buffing... [Waxx] is Wax on! [Buff] Buffing... [Buff] Exiting BuffTask via interrupt. [Waxx] Exiting WaxOnTask via interrupt.
从代码中可以看到,Car的构造器中,单个的Lock将产生一个Condition对象,这个对象被用来管理任务之间的通信。但是,这个Condition对象不包含任何有关处理状态的信息,因此你需要管理额外的表示处理状态的信息,即boolean waxOn。
注意:每个lock()的调用都必须紧跟一个try-finally子句,用来保证在所有情况下都可以释放锁。在使用内建版本时,任务在可以调用await(),signal()或signalAll()之前,必须拥有这个锁。
另外还需要注意的是,这个解决方案比之前一个更加复杂,在本例中这种复杂性并未使你收货更多。Lock和Condition对象只有在更加困难的多线程问题中才是必需的。
时间: 2024-10-04 01:09:11