程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> JAVA綜合教程 >> java多線程中synchronize鎖的使用和學習,Thread多線程學習(二),synchronizethread

java多線程中synchronize鎖的使用和學習,Thread多線程學習(二),synchronizethread

編輯:JAVA綜合教程

java多線程中synchronize鎖的使用和學習,Thread多線程學習(二),synchronizethread


synchronize我的理解是為了保證程序中的原子性和一致性,即當你有兩個線程同時操作一段代碼的時候,要讓這段代碼的執行是在任何狀態下都是正確的,首先要保證synchronize的使用要對同一個對象和同一把鎖使用。

 

[java] view plain copy    print?在CODE上查看代碼片派生到我的代碼片
  1. <span >public class TraditionalThreadSynchronized {  
  2.       
  3.       
  4.     public static void main(String[] args) {  
  5.         TraditionalThreadSynchronized test =new TraditionalThreadSynchronized();  
  6.         test.init();//創建同一個對象  
  7.     }  
  8.   
  9.     private void init(){  
  10.         OutPuter outPuter =new OutPuter();  
  11.         new Thread(new Runnable() {  
  12.             @Override  
  13.             public void run() {  
  14.                 try {  
  15.                     while(true){  
  16.                         Thread.sleep(10);  
  17.                         outPuter.outer("abcdefg");  
  18.                     }  
  19.                 } catch (InterruptedException e) {  
  20.                     e.printStackTrace();  
  21.                 }  
  22.             }  
  23.         }).start();//線程1  
  24.         new Thread(new Runnable() {  
  25.             @Override  
  26.             public void run() {  
  27.                 try {  
  28.                     while(true){  
  29.                         Thread.sleep(10);  
  30.                         outPuter.outer("123456789");  
  31.                     }  
  32.                 } catch (InterruptedException e) {  
  33.                     e.printStackTrace();  
  34.                 }  
  35.             }  
  36.         }).start();//線程2  
  37.     }  
  38.     class OutPuter {  
  39.         public synchronized void outer(String name) {  
  40.                 for(int i = 0;i<name.length();i++){  
  41.                     System.out.print(name.charAt(i));  
  42.                 }  
  43.                 System.out.println();  
  44.         }  
  45.     }  
  46. }</span>  


我們想要打印的結果是abcdefg和123456789交替打印輸出,但是輸出結果卻是下圖

 

 

我們發現打印的結果是兩個String交替打印出來的,所以這個線程現在是不安全的,那麼此時我們就需要使用synchronize保持兩個線程的原子性,下面我們把上面程序中的OutPut方法加上synchronize鎖試一下

 

[java] view plain copy    print?在CODE上查看代碼片派生到我的代碼片
  1. <span >  class OutPuter {  
  2.         public void outer(String name) {  
  3.                 synchronized (name) {  
  4.                     for(int i = 0;i<name.length();i++){  
  5.                         System.out.print(name.charAt(i));  
  6.                     }  
  7.                     System.out.println();  
  8.                 }  
  9.         }  
  10.     }</span>  



 

我們發現加了synchronize關鍵字的鎖以後還是會出現這種線程不安全的情況,那是為什麼呢?原因就出在這個鎖name上,因為兩個線程中的name一個是abcdefg一個是123456789,兩個鎖根本不是一個鎖,所以線程也是不安全的,那麼我們再把上面的方法修改一下

 

[java] view plain copy    print?在CODE上查看代碼片派生到我的代碼片
  1. <span >class OutPuter {  
  2.         public void outer(String name) {  
  3.                 synchronized (this) {//或者創建一個新的鎖把,this換成鎖也可以,此處的this指的是outer這個對象  
  4.                     for(int i = 0;i<name.length();i++){  
  5.                         System.out.print(name.charAt(i));  
  6.                     }  
  7.                     System.out.println();  
  8.                 }  
  9.         }  
  10.     }</span>  


我們發現此時,上面的程序運行不會出現線程安全問題。

 

我們此時把上面的syn加在outer上面也是可以的

 

[java] view plain copy    print?在CODE上查看代碼片派生到我的代碼片
  1. class OutPuter {  
  2.         public synchronized void outer(String name) {  
  3.                     for(int i = 0;i<name.length();i++){  
  4.                         System.out.print(name.charAt(i));  
  5.                     }  
  6.                     System.out.println();  
  7.         }  
  8.     }  

 這樣也是可以實現線程安全的,但是一般情況下synchronize在一段代碼中只要使用一次就夠了,因為多個synchronize可能會出現死鎖問題!

 

此時我們把上面的OutPuter類修改一下

 

[java] view plain copy    print?在CODE上查看代碼片派生到我的代碼片
  1. class OutPuter {  
  2.     public  void outer(String name) {  
  3.         synchronized (this) {  
  4.             for(int i = 0;i<name.length();i++){  
  5.                 System.out.print(name.charAt(i));  
  6.             }  
  7.             System.out.println();  
  8.         }  
  9.     }  
  10.     public synchronized void outer2(String name) {  
  11.             for(int i = 0;i<name.length();i++){  
  12.                 System.out.print(name.charAt(i));  
  13.             }  
  14.             System.out.println();  
  15.     }  
  16. span >   }</span>  

 

然後把上面的outPuter.outer(“123456789”)改成outPuter.outer2(“123456789”)

 


 

此時還能保證線程安全麼,也就是說output和output2會保持互斥麼?當然也是可以的,因為此時的兩個鎖代表的也是同一把鎖,都是代表當前的對象,而當前對象此時是一個對象,所以是可以實現我們想要的效果的。

 

那麼此時我們把上面的

 

然後把上面的outPuter.outer(“123456789”)改成new outPuter().outer(“123456789”)

 

 

我們會發現依然會出現線程安全問題,那是為什麼呢 ?那是因為我們每次new的OutPuter()並不是同一個對象。所以說明synchronize既要保證是同一個對象,又要保證是同一把鎖。

此時我們再加一個output3方法

 

 

[java] view plain copy    print?在CODE上查看代碼片派生到我的代碼片
  1. public static synchronized void outer3(String name) {  
  2.         for(int i = 0;i<name.length();i++){  
  3.             System.out.print(name.charAt(i));  
  4.         }  
  5.         System.out.println();  
  6. span >   }</span>  

 

注意這個output3方法是靜態的,那麼我們需要把OutPuter類也改成靜態類

 

然後把上面的outPuter.outer(“123456789”)改成outPuter.outer3(“123456789”)

 


答案是不行的,因為此時我們使用的output3中的鎖是類鎖,而output中的鎖是當前對象鎖,根本不是一把鎖,那麼此時我們要是想讓output和output3同步需要怎麼做呢?我們把output中的this改成OutPuter.class就可以實現同步了。此時我們兩個方法的鎖就都是類鎖了,即為同一把鎖。

線程還在學習中,學習是痛苦的,但是我希望能真正的堅持做一件事情!

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved