首先是一段代碼:
1 public class HasSelfPrivateNum { 2 public void addI(String username){ 3 try { 4 int num=0; 5 if(username.equals("a")){ 6 num=100; 7 System.out.println("a set over! "); 8 Thread.sleep(2000); 9 }else{ 10 num=200; 11 System.out.println("b set over! "); 12 } 13 System.out.println(username+" num="+num); 14 } catch (InterruptedException e) { 15 e.printStackTrace(); 16 } 17 } 18 }
上述代碼中的含義是HasSelfPrivateNum對象的A和B的判斷
之后有兩個線程:
1 public class ThreadA extends Thread { 2 private HasSelfPrivateNum numRef; 3 public ThreadA(HasSelfPrivateNum numRef){ 4 super(); 5 this.numRef=numRef; 6 } 7 8 public void run(){ 9 super.run(); 10 numRef.addI("a"); 11 } 12 }
1 public class ThreadB extends Thread{ 2 private HasSelfPrivateNum numRef; 3 public ThreadB(HasSelfPrivateNum numRef){ 4 super(); 5 this.numRef=numRef; 6 } 7 8 public void run(){ 9 super.run(); 10 numRef.addI("b"); 11 } 12 }
我們可以看出來線程A和線程B中我們創建了HasSelfPrivateNum實例。
運行結果中可以看出來,這個程序不存在非線程安全性問題,為什么呢,因為這個變量是方法內部的,方法內部的變量是私有的特性造成了線程安全,並且這個其本身永遠線程安全。接下來吧int num這一行代碼放在方法之外我們會看到什么呢?
這時我們會看到線程不安全了,兩個對象同時操作了業務中的實例變量,所以發生了線程不安全的問題,原因是沒有同步,為了讓線程安全我們可以家一個同步鎖來解決這個問題:
加了同步鎖之后運行就安全了,直到A線程執行完成之后在會執行B線程,如果一個線程沒有執行完畢,那么其他線程就無法訪問這個線程。和之前那個同步鎖的道理是一樣的,這就是線程的同步.
以上就是線程同步的道理;
下面是線程的異步:
在剛才的程序上在修改main方法中的代碼為:
同時創建兩個對象然后再兩個線程中運行我們會發現運行結果:
我們現在比較一下兩個結果:
和
我們會發現在同步的時候,執行方式為執行A線程直到A線程完全執行完畢之后,再去執行B,原因是因為只有一個Has對象,資源存在競爭關系,當我們使用同步鎖的時候就會受到同步機制的影響,當A線程占用了這個對象的資源的時候,其他線程就無法訪問這個資源了,直到A執行完畢之后,釋放了這個資源,這個時候B線程才有資格去拿到這個線程.我們把這個機制叫做同步.
那個第二個輸出方式就和前一個不一樣了,這種打印效果就是異步的.兩個線程訪問了兩個不同的對象,這兩個不同的對象產生了兩個鎖,所以一個線程中一個對象的鎖並鎖不住其他對象,所以就會這樣輸出.
結論:Java中synhronized關鍵字鎖住的是一個對象,而不是一個方法或者一段代碼.
=========================================
