初涉java多線程(二)

原文:[url]http://huagenli.iteye.com/blog/511414[/url] 最後的代碼如下:
/**=============================================================================
* 文件:ThreadDemo_06.java
* 描述:爲什麼造成線程的不同步。
* =============================================================================
*/

1. class ThreadDemo extends Thread{
2. //共享一個靜態數據成員
3. private static String szShareData = "";
4.
5. ThreadDemo(){
6. }
7.
8. ThreadDemo(String szName){
9. super(szName);
10. }
11.
12. public void run(){
13. // 爲了更清楚地看到不正確的結果,這裏放一個大的循環
14.   for (int i = 0; i < 50; i++){
15. if (this.getName().equals("Thread1")){
16.      synchronized(szShareData){
17. szShareData = "這是第 1 個線程";
18. // 爲了演示產生的問題,這裏設置一次睡眠
19.      try{
20. Thread.sleep((int)Math.random() * 100);
21. catch(InterruptedException e){
22. }
23. // 輸出結果
24. System.out.println(this.getName() + ":" + szShareData);
25. }
26. }else if (this.getName().equals("Thread2")){
27. synchronized(szShareData){
28. szShareData = "這是第 1 個線程";
29. // 爲了演示產生的問題,這裏設置一次睡眠
30.       try{
31. Thread.sleep((int)Math.random() * 100);
32. catch(InterruptedException e){
33. }
34. // 輸出結果
35. System.out.println(this.getName() + ":" + szShareData);
36. }
37. }
38. }
39. }
40.
41. class ThreadMain{
42. public static void main(String argv[]){
43. ThreadDemo th1 = new ThreadDemo("Thread1");
44. ThreadDemo th2 = new ThreadDemo("Thread2");
45.
46. th1.start();
47. th2.start();
48. }
49. }

並且在最後提出了問題:
這段代碼的共享成員是一個類中的靜態成員,按理說,這裏進入共享代碼時得到的鎖應該是同樣的鎖,而實際上以上程序的輸入卻是不同步的,爲什麼呢??

...按理說,這裏進入共享代碼時得到的鎖應該是同樣的鎖...這句話說得太隱晦,是說到得是同一把鎖,還是說得到得都是對象鎖? 剛學java同步兩週,我大膽的來解決最後的問題:

synchronized(YourClassName.class ):當前線程得到的是YourClassName的Class鎖,那麼在當前線程釋放此Class鎖之前,別的線程沒有機會訪問YourClassName裏的一切。

我翻閱了幾本書,沒有得到以下明文,下面是我的[b]推斷[/b]:

synchronized(private static 實例變量):當前線程得到的是訪問private static 實例變量的對象的鎖。所以thread1、thread2得到的是不同的對象鎖。假設thread1運行到最後代碼中的16行,此時得到的是對象一的鎖,然後程序改變了szShareData的引用(引用了別的地址),接着小睡片刻; thread2搶佔時間片,執行到16行,得到對象二的鎖,改變了szShareData的引用,小睡片刻;thread1搶佔時間片(這是假設,thread1有可能在N個時間片後執行),執行輸出結果,其實輸出的是thread2改變後的szShareData,這樣就出現了紊亂。如果觀察的不是很明顯,可以把sleep改成這樣:Thread.sleep(2)。

改正:把synchronized(private static 實例變量)改成synchronized(YourClassName.class );或者把方法(裏面對static實例變量訪問)改寫成public static synchronized的,這樣獲得的鎖與synchronized(YourClassName.class )獲得的是[b]同一把鎖[/b]。^..^ Thread.sleep(2)期間線程不會釋放鎖。

結論:synchronized(private static 實例變量):當前線程得到的是訪問private static 實例變量的對象的鎖。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章