zoukankan      html  css  js  c++  java
  • [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

  • 相关阅读:
    ERROR 000732:Output Geodatabase:Dataset Database ConnectionsConnection to localhost.sdeSDE.Dataset does not exist or is not supported
    【转】通过 INotifyPropertyChanged 实现观察者模式
    Fatal NI connect error 6413的解决办法 http://www.itpub.net/thread-107518-1-1.html
    Oracle impdp的ignore及 fromuser / touser 功能
    进度条插件使用demo
    两个div并列居中显示——当display:inline-block;时,两个div无法对齐即一高一矮
    两个div并列居中显示——当display:inline;时,div的宽高不起作用即两个div重叠显示
    轮播插件unslider.min.js使用demo
    WEB网页如何让背景图片跟随可视窗口自适应大小
    火狐浏览器不支持location.reload()(以改变页面大小时重新刷新页面为例)
  • 原文地址:https://www.cnblogs.com/TonyYPZhang/p/5560260.html
Copyright © 2011-2022 走看看