当线程任务之间需要进行协作时,关键是要考虑这些任务之间的握手。为实现任务之间的握手,我们可以使用基础特性:互斥。互斥可以确保另有一个任务对某个信号进行响应,这样就可以根除任务之间对某个资源的竞争条件。我们可以提供一途径,任务可以将自身挂起,直到某一个外部条件发生变化时,可以让这个任务重新唤醒继续执行,这个种挂起,唤醒的关系,我们可以使用通过Object类的wait()和notify()/notifyAll()方法来实现。
调用wait()方法时,会释放锁而挂起任务自身,直到另一个任务调用notify()或notifyAll()方法来唤醒wait()挂起的任务,这样wait()挂起的任务可以继续执行。
例子:
一个任务将蜡涂到Car上,一个抛光它。抛光任务在涂蜡任务完成之前,是不能执行基工作的,而涂蜡任务在涂另一层蜡之前,必须等抛光任务完成。WaxOn和WaxOff都使用了Car对象,该对象在这些任务等待条件变化的时候,使用wait()和notifyAll()来挂起和重新启动这些任务:
class Car {
//表示是否上蜡
private boolean waxOn = false;
public synchronized void waxed(){
waxOn = true; //ready to buffed
notifyAll();
}
public synchronized void buffed(){
waxOn = false; //ready for another coat to wax
notifyAll();
}
public synchronized void waitForWaxing() throws InterruptedException{
while(!waxOn){
wait();
}
}
public synchronized void waitForBuffing() throws InterruptedException{
while(waxOn){
wait();
}
}
}
class WaxOn implements Runnable{
private Car car;
public WaxOn(Car car){
this.car = car;
}
@Override
public void run() {
try {
while(!Thread.interrupted()){
System.out.println("Wax On.");
//TimeUnit.MILLISECONDS.sleep(200);
Thread.sleep(200);
car.waxed();
car.waitForBuffing();
}
} catch (InterruptedException e) {
System.err.println("exiting WaxOn interrupt.");
}
System.out.println("ending wax on task.");
}
}
class WaxOff implements Runnable{
private Car car;
public WaxOff(Car car){
this.car = car;
}
@Override
public void run() {
try {
while(!Thread.interrupted()){
System.out.println("Wax Off.");
car.waitForWaxing();
//TimeUnit.MILLISECONDS.sleep(200);
Thread.sleep(200);
car.buffed();
}
} catch (InterruptedException e) {
System.err.println("exiting WaxOff interrupt");
}
System.out.println("ending wax off task.");
}
}
public class WaxOMatic{
public static void main(String[] args) throws InterruptedException{
Car car = new Car();
/*ExecutorService es = Executors.newCachedThreadPool();
es.execute(new WaxOff(car));
es.execute(new WaxOn(car));
TimeUnit.SECONDS.sleep(5);
es.shutdownNow();//shutdown all taskl
*/
Thread t1 = new Thread(new WaxOff(car));
Thread t2 = new Thread(new WaxOn(car));
t1.start();
t2.start();
Thread.sleep(4000);
t1.interrupt();
t2.interrupt();
}
}