線程同步 wait()、notify()

線程安全

很重要的概念。
多線程訪問同一段代碼,不會產生不確定的結果。則可以說這段代碼是線程安全的。

常用方法

調用sleep()的時候,鎖並沒有被釋放,調用yield()也屬於這種情況;而wait()方法會將鎖釋放。
只能在同步控制方法或同步控制塊裏面調用 wait()、notify()、notifyAll()。如果在非同步控制塊中調用這些方法,能通過編譯但運行會出錯,得到IllegalMonitorStateException異常。
當調用某個ExecutorService的shutdownNow()時,它會調用 所有 由它控制的 線程的interrupt()。

Thread.yield()告訴java線程調度器“重要的部分我已經完成,此刻可以將我掛起,切換給其他線程執行”。這個函數可用可不用,但用了它更容易按照自己的掌控去切換線程,從而驗證一些東西。

調用wait()時,執行兩個動作:掛起線程,釋放鎖。
別的地方調用notifyAll(),將喚醒wait()所掛起的線程。在線程繼續運行之前將重新獲得上次wait()調用時釋放的鎖。

使用notify()時,在衆多等待同一個鎖的任務中只有一個會被喚醒。
notifyAll()喚醒所有等待同一個鎖的任務。注意,這並不意味着在程序的任何地方,任何被wait()掛起的線程都會被喚醒,。當notifyAll()因爲某個特定鎖而被調用時,只有等待這個鎖的任務纔會被喚醒。

微笑打蠟、拋光在多個線程中交替進行。
需要一個狀態切換的標誌位,兩對wait()、notify()操作。
一:Thinking in  Java 的例子
//: concurrency/waxomatic/WaxOMatic.java
// Basic task cooperation.
import java.util.concurrent.*;

class Car {
private boolean waxOn = false; //true表示打完蠟該拋光了
public synchronized void waxed() {// 已打蠟,可以拋光了
waxOn = true;
System.out.println("waxed!");
notifyAll();
}
public synchronized void buffed() {// 已拋光,(下輛車)可以打蠟啦
waxOn = false;
System.out.println("buffed!");
notifyAll();
}
public synchronized void waitForWaxing() //已打蠟情況下返回
throws InterruptedException {
while(waxOn == false)
wait();
}
public synchronized void waitForBuffing() //已拋光情況下返回
throws InterruptedException {
while(waxOn == true)
wait();
}
}

class Wax implements Runnable {
private Car car;
public Wax(Car c) { car = c; }
public void run() {
try {
while(!Thread.interrupted()) {
TimeUnit.MILLISECONDS.sleep(200);
car.waxed();
car.waitForBuffing();
}
} catch(InterruptedException e) {
System.out.println("Exiting via interrupt");
}
System.out.println("Ending Wax On task");
}
}

class Buff implements Runnable {
private Car car;
public Buff(Car c) { car = c; }
public void run() {
try {
while(!Thread.interrupted()) {
car.waitForWaxing();
TimeUnit.MILLISECONDS.sleep(200);
car.buffed();
}
} catch(InterruptedException e) {
System.out.println("Exiting via interrupt");
}
System.out.println("Ending Wax Off task");
}
}

public class WaxOMatic {
public static void main(String[] args) throws Exception {
Car car = new Car();
ExecutorService exec = Executors.newCachedThreadPool();
exec.execute(new Buff(car));
exec.execute(new Wax(car));
TimeUnit.SECONDS.sleep(2); // Run for a while...
exec.shutdownNow(); // Interrupt all tasks
}
} /*
waxed!
buffed!
waxed!
buffed!
waxed!
buffed!
waxed!
buffed!
waxed!
buffed!
Exiting via interrupt
Ending Wax On task
Exiting via interrupt
Ending Wax Off task
*/
調試時可以看到有三個線程,很直觀。

 
//wait() notify()全放在Car類中處理
import java.util.concurrent.*;
class Car {
private boolean waxOn = false; // true表示打完蠟該拋光了
public synchronized void wax() throws InterruptedException {
while (waxOn == true)
wait();
TimeUnit.MILLISECONDS.sleep(100);
waxOn = true;
System.out.println("waxed!");
notifyAll();
}
public synchronized void buff() throws InterruptedException {
while (waxOn != true)
wait();
TimeUnit.MILLISECONDS.sleep(100);
waxOn = false;
System.out.println("buffed!");
notifyAll();
}
}
class Wax implements Runnable {
private Car car;
public Wax(Car car) {
this.car = car;
}
public void run() {
try {
while (!Thread.interrupted()) {
car.wax();
}
} catch (InterruptedException e) {
System.out.println("Wax Exiting via interrupt");
}
}
}
class Buff implements Runnable {
private Car car;
public Buff(Car car) {
this.car = car;
}
public void run() {
try {
while (!Thread.interrupted()) {
car.buff();
}
} catch (InterruptedException e) {
System.out.println("Buff Exiting via interrupt");
}
}
}
public class WaxOMatic {
public static void main(String[] args) throws Exception {
ExecutorService exec = Executors.newCachedThreadPool();
Car car = new Car();
exec.execute(new Buff(car));
exec.execute(new Wax(car));
TimeUnit.SECONDS.sleep(1); // Run for a while...
exec.shutdownNow(); // Interrupt all tasks
}
}
/*
waxed!
buffed!
waxed!
buffed!
waxed!
buffed!
waxed!
buffed!
waxed!
buffed!
Wax Exiting via interrupt
Buff Exiting via interrupt
*/
 來自CODE的代碼片
全放在Car類中處理.java

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章