java多線程中wait和sleep的區別

今天看張老師的多線程,想起了以前看過的一個例子,關於生產者與消費者經典案例,我覺的這種代碼應該反覆思考研究。

package msb.Thread;

public class ProducerConsumer {
	public static void main(String[] args) {
		SyncStack ss = new SyncStack();
		Producer p = new Producer(ss);
		Consumer c = new Consumer(ss);
//		new Thread(p).start();
//		new Thread(p).start();
		new Thread(p).start();
		new Thread(c).start();
	}
}

class WoTou {
	int id;

	WoTou(int id) {
		this.id = id;
	}

	public String toString() {
		return "WoTou : " + id;
	}
}

class SyncStack {
	int index = 0;
	WoTou[] arrWT = new WoTou[6];

	public synchronized void push(WoTou wt) {
		while (index == arrWT.length) {
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		this.notifyAll();
		arrWT[index] = wt;
		System.out.println("生產了:" + wt);
		index++;
	}

	public synchronized WoTou pop() {
		while (index == 0) {
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		this.notifyAll();
		index--;
		WoTou wt=arrWT[index];
		System.out.println("消費了: " + wt);
		return arrWT[index];
	}
}

class Producer implements Runnable {
	SyncStack ss = null;

	Producer(SyncStack ss) {
		this.ss = ss;
	}

	public void run() {
		for (int i = 0; i < 20; i++) {
			WoTou wt = new WoTou(i);
			ss.push(wt);		
			try {
				Thread.sleep((int) (Math.random() * 200));
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}

class Consumer implements Runnable {
	SyncStack ss = null;

	Consumer(SyncStack ss) {
		this.ss = ss;
	}

	public void run() {
		for (int i = 0; i < 20; i++) {
			WoTou wt = ss.pop();
			try {
				Thread.sleep((int) (Math.random() * 1000));
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}

剛開始的時候我將對窩頭的打印寫在了run方法裏面,結果在在控制檯打印的結果很出乎我的意料,後來我才瞭解到是我對wait和sleep的理解不深,接下來是wait和sleep的區別。

  1. 這兩個方法來自不同的類分別是ThreadObject
  2. 最主要是sleep方法沒有釋放鎖,而wait方法釋放了鎖,使得其他線程可以使用同步控制塊或者方法。 
  3. waitnotifynotifyAll只能在同步控制方法或者同步控制塊裏面使用,而sleep可以在任何地方使用(使用範圍)

  synchronized(x){

  x.notify()

  //或者wait()

  }

        4.sleep必須捕獲異常,而waitnotifynotifyAll不需要捕獲異常

  java 線程中的sleepwait有一個共同作用,停止當前線程任務運行,但他們存在一定的不同。首先我們來看一下sleep的構造方法。

sleep(long millis)          
Causes the currently executing thread to sleep (temporarily cease execution) for the specified number of milliseconds, subject to the precision and accuracy of system timers and schedulers.
sleep(long millis, int nanos) 
 Causes the currently executing thread to sleep (cease execution) for the specified number of milliseconds plus the specified number of nanoseconds, subject to the precision and accuracy of system timers and schedulers.

   sleep方法屬於Thread類中方法,表示讓一個線程進入睡眠狀態,等待一定的時間之後,自動醒來進入到可運行狀態,不會馬上進入運行狀態,因爲線程調度機制恢復線程的運行也需要時間,一個線程對象調用了sleep方法之後,並不會釋放他所持有的所有對象鎖,所以也就不會影響其他進程對象的運行。但在sleep的過程中有可能被其他對象調用它的interrupt(),產生InterruptedException異常,如果你的程序不捕獲這個異常,線程就會異常終止,進入TERMINATED狀態,如果你的程序捕獲了這個異常,那麼程序就會繼續執行catch語句塊(可能還有finally語句塊)以及以後的代碼。

  注意sleep()方法是一個靜態方法,也就是說他只對當前對象有效,通過t.sleep()t對象進入sleep,這樣的做法是錯誤的,它只會是使當前線程被sleep 而不是t線程。 

wait方法
  void wait(long timeout)
   Causes the current thread to wait until either another thread invokes the notify() method or the notifyAll() method for this object, or a specified amount of time has elapsed.
  void wait(long timeout, int nanos)
  Causes the current thread to wait until another thread invokes the notify() method or the notifyAll() method for this object, or some other thread interrupts the current thread, or a certain amount of real time has elapsed.

  wait屬於Object的成員方法,一旦一個對象調用了wait方法,必須要採用notify()notifyAll()方法喚醒該進程;如果線程擁有某個或某些對象的同步鎖,那麼在調用了wait()後,這個線程就會釋放它持有的所有同步資源,而不限於這個被調用了wait()方法的對象。wait()方法也同樣會在wait的過程中有可能被其他對象調用interrupt()方法而產生

  InterruptedException,效果以及處理方式同sleep()方法。


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