怎麼辦,好幾天沒寫博客了,心裏感覺不踏實。水一篇吧,水水更健康。在看Java線程這本書的電子版,看到第四章notify、wait、notifyAll這幾個方法,前面的notify和wait還好,比較簡單,就是需要注意的是notify和wait方法必須放在同步代碼中。可是爲什麼要這樣呢?原因是如果不將notify和wait放到同步代碼中的話,他們之間可能會產生競態條件。現設有兩個線程,如果不將notify和wait放在同步代碼中可能發生如下情況:
一、第一個線程檢查條件,確定需要等待。
二、第二個線程設定條件。
三、第二個線程調用notify()方法,本次調用因爲沒有其他的等待線程而直接返回。
四、第一個線程調用wait()。
附上一段關於notify和wait的Android代碼:
package com.wly.testwait_notify;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
public class MainActivity extends Activity {
int count = 0;
Button b;
CountThread countThread;
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
b.setText(msg.arg1 + "");
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
b = new Button(this);
b.setText("0");
this.setContentView(b);
countThread = new CountThread();
countThread.start();
b.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(countThread.isAlive()) {
countThread.wakeup();
}
}
});
}
class CountThread extends Thread {
@Override
public void run() {
super.run();
while(count < 20) {
sendMsg();
try {
sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//發送通知,並進入等待狀態,注意wait()只能位於synchronized代碼塊中
public synchronized void sendMsg() {
Message msg = new Message();
msg.arg1 = count ++;
handler.sendMessage(msg);
if(count % 5 == 0) {
try {
System.out.println("--等待10秒--");
wait(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
* 喚醒線程,注意notify()只能位於synchronized代碼塊中
*/
public synchronized void wakeup() {
notify();
}
}
}
說出來有點好笑的是,筆者以前想在Android中用wait()結果因爲沒有放到同步代碼塊中,導致一運行就報錯,還以爲Android中不能用wait呢!咳咳,,不要笑啦,進入今天正題NotifyAll。可能是最近辦公室比較吵得原因吧(搶票的搶票,聊天的聊天),使得筆者靜不下心來,於是一個notifyAll盯着看了好久纔看懂。
還是一樣分析,爲什麼要有notifyAll,他和notify有什麼區別嗎?notifyAll用來喚醒一個對象上的多個等待線程。就是說首先這個對象有多個線程等待着使用該對象,其次就是要喚醒所有的線程,讓他們去競爭對象上的鎖。這裏需要注意一下的是:雖然所有該對象上的等待線程都被喚醒了,但他們還需要獲得對象上的鎖才能向下運行。於是當調用notifyAll後還是隻有那個獲取到了鎖的線程才能繼續往下運行。好了,一段notifyAll的測試代碼:
package com.wly.javathread.chap4;
/**
* 測試notifyAll方法
*
* @author wly
*
*/
public class TestNotifyAll implements Runnable {
static ResourcePool mPool;
public static void main(String[] args) {
ResourcePool pool = new ResourcePool();
System.out.println("總資源數:" + pool.resource_max);
TestNotifyAll tn_1 = new TestNotifyAll(pool);
TestNotifyAll tn_2 = new TestNotifyAll(pool);
TestNotifyAll tn_3 = new TestNotifyAll(pool);
TestNotifyAll tn_4 = new TestNotifyAll(pool);
new Thread(tn_1).start();
new Thread(tn_2).start();
new Thread(tn_3).start();
new Thread(tn_4).start();
}
@Override
public void run() {
while(true) {
mPool.getResource(2);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
mPool.freeResource(1);
}
}
public TestNotifyAll(ResourcePool pool) {
this.mPool = pool;
}
static class ResourcePool {
int resource_max = 10; //資源最大數量
int resource_count = 0; //當前佔用資源數量
/**
* 獲取資源
* @param num
*/
public synchronized void getResource(int num) {
if((resource_count + num) <= resource_max) { //有可用資源,領取使用
resource_count += num;
System.out.println("線程" + Thread.currentThread().getId() + "拿到2個資源");
System.out.println("剩餘資源數:" + (resource_max -resource_count));
} else { //無可用資源,等
try {
System.out.println("資源數量不夠,線程" + Thread.currentThread().getId() + ":進入等待狀態");
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
* 釋放資源
* @param num
*/
public synchronized void freeResource(int num) {
if(num <= (resource_count)) {
resource_count -= num;
System.out.println("釋放" + num + "個資源,當前剩餘資源" + (resource_max-resource_count));
notifyAll();
}
}
}
}
運行結果如下:
總資源數:10
線程9拿到2個資源
剩餘資源數:8
線程11拿到2個資源
剩餘資源數:6
線程8拿到2個資源
剩餘資源數:4
線程10拿到2個資源
剩餘資源數:2
釋放1個資源,當前剩餘資源3
線程9拿到2個資源
剩餘資源數:1
釋放1個資源,當前剩餘資源2
線程11拿到2個資源
剩餘資源數:0
釋放1個資源,當前剩餘資源1
資源數量不夠,線程8:進入等待狀態
釋放1個資源,當前剩餘資源2
線程10拿到2個資源
剩餘資源數:0
釋放1個資源,當前剩餘資源1
資源數量不夠,線程9:進入等待狀態
釋放1個資源,當前剩餘資源2
線程11拿到2個資源
剩餘資源數:0
釋放1個資源,當前剩餘資源1
資源數量不夠,線程8:進入等待狀態
釋放1個資源,當前剩餘資源2
線程10拿到2個資源
剩餘資源數:0
釋放1個資源,當前剩餘資源1
資源數量不夠,線程11:進入等待狀態
釋放1個資源,當前剩餘資源2
線程9拿到2個資源
剩餘資源數:0
釋放1個資源,當前剩餘資源1
資源數量不夠,線程8:進入等待狀態
釋放1個資源,當前剩餘資源2
線程10拿到2個資源
剩餘資源數:0
可能運行結果需要仔細看才能看出流程,主要就是釋放資源時通知所有等待線程,若此時某個等待線程搶到了鎖會進行資源請求,或者進入等待狀態(資源不夠時)。
O啦~~~
轉載請保留出處:http://blog.csdn.net/u011638883/article/details/18322537
謝謝!!