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ページに示された生産者、消費者のサンプルコードは以下の通りである.
以下に、(1)notifyAllを呼び出すだけで次のエラーが発生します.
これはwait,notify,notifyAllが「ロックされた」環境で動作する必要があるからです.(2)この時点でchefにsleep文を記述してshutdownNowを実行してから正常に終了していない
この場合、waiterはちょうど最後の「料理」を待っていて、この料理を食べ終わった後、退勤して、正常に退出します.(3)この時点でchefにsleep文を記述してshutdownNowを実行していない場合、waiterはwait状態となり、中断される
この場合、waiterは最後の「料理」を待つことができず、退出を中断された.(4)この時点でchefに対してsleep文を記述してshutdownNowを実行していない場合,waiterはwait状態にあり中断されるが,出力は雑である.
(5)shutdownNowを実行した後、waiterはwait状態にあり、中断され、chefはsleep状態にあり、中断される
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)