Javaマルチスレッドの生産者、消費者(十三)

14980 ワード

1.なぜwhileループを使用してwait呼び出しを囲むのですか?複数のwaiterがシェフの「料理」を競争している場合、1つのwaiterが「料理」を奪った後、他の人は料理を奪うことができません.もう一つwhile条件を判断すると、その奪われたwaiterに条件を満たされた可能性があるので、またwaitせざるを得ない.しかし、このときその奪ったwaiterが条件変更まで実行されなかったらどうするのでしょうか.この例のコードでは説明できないようですが、後で適切なコードを見てから説明します.2.wait、notify、notifyAllは必ず「ロックあり」の環境で操作してください.3.どのオブジェクトロックでwait操作を呼び出すか、どのオブジェクトロックでnotify、notifyAll操作を呼び出すか.4.interrupt割込みについてsleep,wait状態で割込みが発生した場合、スレッドはInterruptedExeceptionを放出して異常終了するが、whileサイクル判定Threadに進む可能性もある.interrupted()で正常に終了しました.「Thinking in java」709ページに示された生産者、消費者のサンプルコードは以下の通りである.
package org.fan.learn.thread.share;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
/**
 * Created by fan on 2016/7/5.
 */
class Meal {
    private final int orderNum;
    Meal(int orderNum) {
        this.orderNum = orderNum;
    }
    @Override
    public String toString() {
        return " Meal : " + orderNum ;
    }
}
//     
//   meal         ,     ,      
class Waiter implements Runnable {
    Restaurant restaurant;
    public Waiter(Restaurant restaurant) {
        this.restaurant = restaurant;
    }
    public void run() {
        try {
            while (!Thread.interrupted()) {
                //     waiter  ,      ,   waiter   notify
                synchronized (this) {
                    while (restaurant.meal == null) {
                        wait();
                    }
                }
                System.out.println("Waiter get " + restaurant.meal);
                synchronized (restaurant.chef) {
                    restaurant.meal = null;
                    //    notifyAll     :IllegalMonitorStateException
                    //notifyAll();
                    //  chef   wait
                    restaurant.chef.notifyAll();
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
class Chef implements Runnable {
    Restaurant restaurant;
    int count;
    public Chef(Restaurant restaurant) {
        this.restaurant = restaurant;
    }
    public void run() {
        try {
            while (!Thread.interrupted()) {
                synchronized (this) {
                    //      chef  ,      ,   chef   notify
                    while (restaurant.meal != null) {
                        wait();
                    }
                }
                System.out.println("Order up");
                if (++count == 10) {
                    System.out.println("exe shutdownNow");
                    restaurant.exe.shutdownNow(); //       interrupt
                }
                synchronized (restaurant.waiter) {
                    restaurant.meal = new Meal(count);
                    //  waiter   wait
                    restaurant.waiter.notifyAll();
                    System.out.println("**********");
                }
                //        
                TimeUnit.MILLISECONDS.sleep(100);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
public class Restaurant {
    Meal meal;
    //waiter、chef     restaurant  。
    Waiter waiter = new Waiter(this);
    Chef chef = new Chef(this);
    ExecutorService exe = Executors.newCachedThreadPool();
    Restaurant () {
        exe.execute(waiter);
        exe.execute(chef);
    }
    public static void main(String[] args) {
        new Restaurant();
    }
}

以下に、(1)notifyAllを呼び出すだけで次のエラーが発生します.
Order up
Exception in thread "pool-1-thread-2" java.lang.IllegalMonitorStateException
    at java.lang.Object.notifyAll(Native Method)
    at org.fan.learn.thread.Chef.run(Restaurant.java:74)
    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)

これはwait,notify,notifyAllが「ロックされた」環境で動作する必要があるからです.(2)この時点でchefにsleep文を記述してshutdownNowを実行してから正常に終了していない
Order up
**********
Waiter get  Meal : 1
Order up
**********
Waiter get  Meal : 2
Order up
**********
Waiter get  Meal : 3
Order up
**********
Waiter get  Meal : 4
Order up
**********
Waiter get  Meal : 5
Order up
**********
Waiter get  Meal : 6
Order up
**********
Waiter get  Meal : 7
Order up
**********
Waiter get  Meal : 8
Order up
**********
Waiter get  Meal : 9
Order up
exe shutdownNow
**********
Waiter get  Meal : 10

この場合、waiterはちょうど最後の「料理」を待っていて、この料理を食べ終わった後、退勤して、正常に退出します.(3)この時点でchefにsleep文を記述してshutdownNowを実行していない場合、waiterはwait状態となり、中断される
Order up
**********
Waiter get  Meal : 1
Order up
**********
Waiter get  Meal : 2
Order up
**********
Waiter get  Meal : 3
Order up
**********
Waiter get  Meal : 4
Order up
**********
Waiter get  Meal : 5
Order up
**********
Waiter get  Meal : 6
Order up
**********
Waiter get  Meal : 7
Order up
**********
Waiter get  Meal : 8
Order up
**********
Waiter get  Meal : 9
Order up
exe shutdownNow
**********
java.lang.InterruptedException
    at java.lang.Object.wait(Native Method)
    at java.lang.Object.wait(Object.java:502)
    at org.fan.learn.thread.Waiter.run(Restaurant.java:35)
    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)

この場合、waiterは最後の「料理」を待つことができず、退出を中断された.(4)この時点でchefに対してsleep文を記述してshutdownNowを実行していない場合,waiterはwait状態にあり中断されるが,出力は雑である.
java.lang.InterruptedException
Order up
    at java.lang.Object.wait(Native Method)
**********
    at java.lang.Object.wait(Object.java:502)
Waiter get  Meal : 1
    at org.fan.learn.thread.Waiter.run(Restaurant.java:35)
Order up
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
**********
Waiter get  Meal : 2
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
Order up
    at java.lang.Thread.run(Thread.java:745)
**********
Waiter get  Meal : 3
Order up
**********
Waiter get  Meal : 4
Order up
**********
Waiter get  Meal : 5
Order up
**********
Waiter get  Meal : 6
Order up
**********
Waiter get  Meal : 7
Order up
**********
Waiter get  Meal : 8
Order up
**********
Waiter get  Meal : 9
Order up
exe shutdownNow
**********

(5)shutdownNowを実行した後、waiterはwait状態にあり、中断され、chefはsleep状態にあり、中断される
Order up
**********
Waiter get  Meal : 1
Order up
**********
Waiter get  Meal : 2
Order up
**********
Waiter get  Meal : 3
Order up
**********
Waiter get  Meal : 4
Order up
**********
Waiter get  Meal : 5
Order up
**********
Waiter get  Meal : 6
Order up
**********
Waiter get  Meal : 7
Order up
**********
Waiter get  Meal : 8
Order up
**********
Waiter get  Meal : 9
Order up
java.lang.InterruptedException
exe shutdownNow
    at java.lang.Object.wait(Native Method)
**********
    at java.lang.Object.wait(Object.java:502)
    at org.fan.learn.thread.Waiter.run(Restaurant.java:36)
    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 org.fan.learn.thread.Chef.run(Restaurant.java:78)
    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)