[Java Concurrent] 多线程合作 wait / notifyAll 的简单案例

本案例描述的是,给一辆汽车打蜡、抛光的场景。

 

Car 是一辆被打蜡抛光的汽车,扮演共享资源的角色。

WaxOnCommand 负责给汽车打蜡,打蜡时需要独占整部车,一次打一部分蜡,等待抛光,然后再打一部分蜡。

BuffCommand 负责给汽车抛光,抛光时需要独占整部车,每一次会将刚打上的蜡抛光,然后等待打蜡,然后再将刚打上的蜡抛光。

WaxOnCommand 、BuffCommand 分别由两个线程相互交替地执行:

  WaxOnCommand 打蜡、等待抛光,BuffCommand 抛光,等待打蜡;

  WaxOnCommand 打蜡、等待抛光,BuffCommand 抛光,等待打蜡;

  WaxOnCommand 打蜡、等待抛光,BuffCommand 抛光,等待打蜡;

  ......

CarWaxBuffDemo 演示这个场景。

 

下面是类之间的关系图。

由于 ExecutorServices 的使用和 Command Pattern 很相似,所以参照其 UML 绘制而成。

 

代码实现:

Car, 可以改变汽车的打蜡状态,可以等待打蜡状态的改变。输出内容到控制台时,会把当前执行线程一一同输出。

 

public class Car {
    
    private boolean isWaxed = false;
    
    public synchronized void waxed(){
        isWaxed = true;
        print(" car is waxed now ");
        notifyAll();
    }
    
    public synchronized void unwaxed(){
        isWaxed = false;
        print(" car is unwaxed now ");
        notifyAll();
    }public synchronized void waitingForReWax() throws InterruptedException{
        while (isWaxed == true){
            wait();
        }
        print(" OK to re-wax ");

    }
    
    public synchronized void waitingForReBuff() throws InterruptedException{
        while (isWaxed == false){
            wait();
        }
        print(" OK to re-Buff ");
    }
    
    public void print(String msg){
        System.out.println("[" + Thread.currentThread().getName() + " ] " + msg);
    }
}

WaxonComman,给汽车打蜡,主要是两个动作:1.等待可以打蜡,2.打蜡。

import java.util.concurrent.TimeUnit;

public class WaxonCommand implements Runnable {

    private Car car;
    
    public WaxonCommand(Car car){
        this.car = car;
    }
    
    @Override
    public void run() {
        try {
            while (true){
                car.waitingForReWax();
                
                print(" WaxOn take action ");
                TimeUnit.MILLISECONDS.sleep(100);                
                
                car.waxed();
            } 
        }catch (Exception e) {
            e.printStackTrace();
        }
        
        try {
            TimeUnit.MILLISECONDS.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }                
        
        print(" Ending WaxOn action ");
    }
    
    public void print(String msg){
        System.out.println("[" + Thread.currentThread().getName() + " ] " + msg);
    }
}

 

buffCommand, 给汽车抛光,主要两个动作:1.等待可以抛光,2. 抛光。

import java.util.concurrent.TimeUnit;

public class BuffCommand implements Runnable{

    private Car car;
    
    public BuffCommand(Car car){
        this.car = car;
    }
    
    @Override
    public void run() {
        try {
            while (true){
                car.waitingForReBuff();

                print(" Buff take action ");
                TimeUnit.MILLISECONDS.sleep(80);
                
                car.unwaxed();
            } 
        }catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        try {
            TimeUnit.MILLISECONDS.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }    
        
        print(" Ending Buff action ");

    }
    
    public void print(String msg){
        System.out.println("[" + Thread.currentThread().getName() + " ] " + msg);
    }
}

演示给汽车交替打蜡、抛光的场景。给 1 秒的时间,让 WaxonCommand / BuffComand 线程进行打蜡、抛光操作,1 秒后,中断他们的操作。

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class CarWaxBuffDemo {

    public static void main() throws InterruptedException{
        ExecutorService exec = Executors.newCachedThreadPool();
        
        Car car = new Car();
        exec.execute(new BuffCommand(car));
        exec.execute(new WaxonCommand(car));
        
        TimeUnit.SECONDS.sleep(1);
        System.out.println(" executor stopping ");
        exec.shutdownNow();
    }
}

输出结果:

在被强制中断前,thread-1 和 thread-2 交替进行打蜡、抛光操作。

[pool-1-thread-1 ]  OK to re-wax 
[pool-1-thread-1 ]  WaxOn take action 
[pool-1-thread-1 ]  car is waxed now 
[pool-1-thread-2 ]  OK to re-Buff 
[pool-1-thread-2 ]  Buff take action 
[pool-1-thread-2 ]  car is unwaxed now 
[pool-1-thread-1 ]  OK to re-wax 
[pool-1-thread-1 ]  WaxOn take action 
[pool-1-thread-1 ]  car is waxed now 
[pool-1-thread-2 ]  OK to re-Buff 
[pool-1-thread-2 ]  Buff take action 
[pool-1-thread-2 ]  car is unwaxed now 
[pool-1-thread-1 ]  OK to re-wax 
[pool-1-thread-1 ]  WaxOn take action 
[pool-1-thread-1 ]  car is waxed now 
[pool-1-thread-2 ]  OK to re-Buff 
[pool-1-thread-2 ]  Buff take action 
[pool-1-thread-2 ]  car is unwaxed now 
[pool-1-thread-1 ]  OK to re-wax 
[pool-1-thread-1 ]  WaxOn take action 
[pool-1-thread-1 ]  car is waxed now 
[pool-1-thread-2 ]  OK to re-Buff 
[pool-1-thread-2 ]  Buff take action 
[pool-1-thread-2 ]  car is unwaxed now 
[pool-1-thread-1 ]  OK to re-wax 
[pool-1-thread-1 ]  WaxOn take action 
[pool-1-thread-1 ]  car is waxed now 
[pool-1-thread-2 ]  OK to re-Buff 
[pool-1-thread-2 ]  Buff take action 
[pool-1-thread-2 ]  car is unwaxed now 
[pool-1-thread-1 ]  OK to re-wax 
[pool-1-thread-1 ]  WaxOn take action 
 executor stopping 
java.lang.InterruptedException
    at java.lang.Object.wait(Native Method)
    at java.lang.Object.wait(Object.java:502)
    at concurrencyCooperation.Car.waitingForReBuff(Car.java:29)
    at concurrencyCooperation.BuffCommand.run(BuffCommand.java:17)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)
java.lang.InterruptedException: sleep interrupted
    at java.lang.Thread.sleep(Native Method)
    at java.lang.Thread.sleep(Thread.java:340)
    at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386)
    at concurrencyCooperation.WaxonCommand.run(WaxonCommand.java:20)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)
[pool-1-thread-2 ]  Ending Buff action 
[pool-1-thread-1 ]  Ending WaxOn action 

 

参考资料 : 

Page 857, wait() and notifyAll(), Thinking in Java

 

posted @ 2016-06-05 10:48  TonyYPZhang  阅读(297)  评论(0编辑  收藏  举报