1. 程式人生 > >Java多執行緒suspend、sleep的控制鎖的釋放的區別

Java多執行緒suspend、sleep的控制鎖的釋放的區別

         因為馬上畢業了,最近一直在複習Java的基礎知識,多執行緒當然是重點了,今天上午一直在看執行緒的生命階段,其中有過時的方法suspend用來掛起一個執行緒。而關於該方法為何被拋棄了,看了開發文件中是這麼描述的:【方法已經遭到反對,因為它具有固有的死鎖傾向。如果目標執行緒掛起時在保護關鍵系統資源的監視器上保持有鎖,則在目標執行緒重新開始以前任何執行緒都不能訪問該資源。如果重新開始目標執行緒的執行緒想在呼叫resume 之前鎖定該監視器,則會發生死鎖。】

看完上面的官方文件,光看文字把頭都看暈了,感覺sleep和suspend對掛起執行緒的操作感覺又模糊了不少,尤其是對鎖的控制上面。

因此就模擬了兩個執行緒,程式碼如下:

package a.b;
public class Test {
	private static final int INDEX = 10;
	public static void main(String[] args) {
		try {
			// 定義執行緒
			Thread tchild = new Thread(new Runnable() {
				public void run() {
					try {
						int a = 0;
						for (long i = 0; i < 1000000; i++) {
						while (a < INDEX)/** 如果在執行這句的時候呼叫了tchild.suspend(),那就不會導致死鎖 */
							a++;
						}
						System.out.println(i);
						/**
						* 如果正好在執行上面這句的時候呼叫了tchild.suspend(),
						* 由於println()方法裡面保持有鎖,
						* 因此,在本執行緒掛起的時候其他的執行緒就無法使用println方法中所持有的鎖,
						* 這就導致suspend方法容易導致死鎖的原因。
						*/
						a = 0;/** 如果在執行這句的時候呼叫了tchid.suspend(),那就不會導致死鎖 *//
					}
				} catch (Throwable e) {e.printStackTrace();}
			}//run
		});
		tchild.start();/**開啟子執行緒*/
		Thread.sleep(2000);/**讓主執行緒停止2s,子執行緒繼續執行2s*/
		tchild.suspend();/**讓子執行緒掛起*/
		
		/**讓子執行緒掛起的情況下再執行主執行緒中的列印操作*/
		for (long i = 0; i < 1000000; i++) {
			System.out.println("主執行緒"+i);
		}
		tchild.resume();//啟用被掛起的執行緒 } catch (Throwable ex) { ex.printStackTrace(); } }
}




實驗結果是:
1)當常量INDEX=10的時候,輸出的結果大部分情況下是:執行到:    
....
子執行緒152463
子執行緒152464
子執行緒152465
此時,列印了子執行緒的資訊過了兩秒後,子執行緒被掛起,但是主執行緒中的內容卻沒有繼續執行,這說明主執行緒已經被阻塞了;
原因是:子執行緒在執行到System.out.println(i);這一句的時候被suspend()方法掛起了,而由於該句呼叫的時候使用了鎖,
即out中的常量public final static PrintStream out = null;此處的out物件就是方法println中使用的鎖物件;因此在被suspend掛起後子執行緒任然持有鎖-out常量,所以當主執行緒執行for迴圈列印資訊的時候System.out.println("主執行緒"+i);,主執行緒根本拿不到鎖,因此造成執行緒死鎖;
2)當常量INDEX=100000000的時候,輸出結果大部分情況下是,執行到:
.....
主執行緒999998
主執行緒999999
子執行緒2605
子執行緒2606
...
子執行緒999998
子執行緒999999
,同樣的道理因為子執行緒並不是在執行System.out.println(i);這一句的時候被suspend()方法掛起的,所以就不會持有列印語句中的鎖-out常量,因此不會產生死鎖現象。
綜合上面的分析:
呼叫suspend方法來掛起一個執行緒A的時候,如果這好在執行一端具有同步鎖的程式碼塊的時候被掛起,那這個同步鎖是不會被釋放的,那麼當執行緒B執行時,如果內部程式碼需要使用到該鎖,而此時的鎖是被執行緒B中程式碼塊持有的,此時就會導致執行緒死鎖。這就是為什麼suspend不安全的地方,因為它無法控制執行緒內部程式碼塊持有的鎖的釋放。
關於sleep呼叫後不會釋放鎖是指的,當執行緒A的同步程式碼塊中呼叫了sleep的使用,該程式碼塊持有的鎖不會被釋放,那麼執行緒B,C,..去執行具有相同鎖物件的程式碼塊的時候就會被阻塞。