java同步和互斥【用具體程序說明】

java同步和互斥【用具體程序說明】

 
         全部對象都自動含有單一的鎖,也就是全部對象都有且只有惟一的鎖,因此當某個任務(線程)訪問一個類A中含有sycnhronized的方法是,那麼在這個線程從該方法返回以前(也就是該方法在當前線程執行完以前),類A中的其餘被該關鍵字標記的方法在其餘的線程中都會被阻塞。
            通俗點說就是,當調用A的含有synchronized的方法是,A會被枷鎖,此時A中其餘含有synchronized方法只有等到前一個方法調用完畢釋放了鎖才能被調用

           具體說明見另外一篇博客<<java同步和互斥【相關原理】》html

        下面看看具體的程序,其中,Timer中的字段num是共享資源java

[java]  view plain  copy
 
  1. package com.bankht.synchronize;  
  2.   
  3. public class TestSync implements Runnable {  
  4.     Timer timer = new Timer();  
  5.   
  6.     public static void main(String[] args) {  
  7.         TestSync test = new TestSync();  
  8.         Thread t1 = new Thread(test);  
  9.         Thread t2 = new Thread(test);  
  10.         t1.setName("t1");  
  11.         t2.setName("t2");  
  12.         t1.start();  
  13.         t2.start();  
  14.     }  
  15.   
  16.     public void run() {  
  17.         timer.add(Thread.currentThread().getName());  
  18.     }  
  19. }  
  20.   
  21. class Timer {  
  22.     private static int num = 0;  
  23.   
  24.     public void add(String name) {  
  25.   
  26.         num++;  
  27.         try {  
  28.             Thread.sleep(1);  
  29.         } catch (InterruptedException e) {  
  30.         }  
  31.         System.out.println(name + ", 你是第" + num + "個使用timer的線程");  
  32.   
  33.     }  
  34. }  


 

[java]  view plain  copy
 
  1. 因爲沒有同步,因此運行結果以下所示   

 

 

t1, 你是第2個使用timer的線程post

t2, 你是第2個使用timer的線程this

 

也就是說當線程一運行到num++的時候被打線程2打斷了,因爲java中遞增和遞減操做均不是原子操做,因此本程序中即便沒有調用sleep,也會出現這種被打斷的狀況spa

下面看看同步的效果.net

[java]  view plain  copy
 
  1. public void add(String name) {  
  2.        synchronized (this) {//同步  
  3.            num++;  
  4.            try {  
  5.                Thread.sleep(1000);  
  6.            } catch (InterruptedException e) {  
  7.            }  
  8.            System.out.println(name + ", 你是第" + num + "個使用timer的線程");  
  9.        }  
  10.    }  


這樣運行結果就會出是正確的線程

 

 

t1, 你是第1個使用timer的線程htm

t2, 你是第2個使用timer的線程對象

可是,下面爲了說明問題把TestSync裏面的run方法改爲以下所示blog

[java]  view plain  copy
 
  1. public void run() {  
  2. /         
  3.            time.add(Thread.currentThread().getName());  
  4.            try {  
  5.                Thread.sleep(1000);//爲了顯示結果,讓其睡眠一秒  
  6.            } catch (InterruptedException ex) {  
  7.                Logger.getLogger(TestSync.class.getName()).log(Level.SEVERE, null, ex);  
  8.            }  
  9.          System.out.println(Thread.currentThread().getName() + "----");  
  10.        }  


 

那麼在此運行就是

 

t1, 你是第1個使用timer的線程

t2, 你是第2個使用timer的線程

t1--------

t2--------

而不是你所想象的

t1, 你是第1個使用timer的線程
t1----
t2, 你是第2個使用timer的線程
t2----

緣由就是在線程t1在睡眠的時候,線程t2切換進來,執行了一次,怎樣獲得正確的結果呢,下面把TestSync裏面的run方法作以下改進就能夠獲得上面預期的結果

[java]  view plain  copy
 
  1. public void run() {  
  2.       synchronized(time){  
  3.            time.add(Thread.currentThread().getName());  
  4.            try {  
  5.                Thread.sleep(3000);  
  6.            } catch (InterruptedException ex) {  
  7.                Logger.getLogger(TestSync.class.getName()).log(Level.SEVERE, null, ex);  
  8.            }  
  9.          System.out.println(Thread.currentThread().getName() + "----");  
  10.        }  
  11.    }  


由於t1先得到time的鎖,因此在執行完run裏面的同步塊以前,即便sleep(),t2也不會執行,由於t2沒有得到time的鎖,且sleep()操做也不釋放鎖(這也是和wait的巨大區別)

附錄:TestSync.java所有代碼

[java]  view plain  copy
 
  1. package com.bankht.synchronize;  
  2.   
  3. import java.util.logging.Level;  
  4. import java.util.logging.Logger;  
  5.   
  6. public class TestSync implements Runnable {  
  7.     Timer timer = new Timer();  
  8.   
  9.     public static void main(String[] args) {  
  10.         TestSync test = new TestSync();  
  11.         Thread t1 = new Thread(test);  
  12.         Thread t2 = new Thread(test);  
  13.         t1.setName("t1");  
  14.         t2.setName("t2");  
  15.         t1.start();  
  16.         t2.start();  
  17.     }  
  18.   
  19. //  public void run() {  
  20. //      timer.add(Thread.currentThread().getName());  
  21. //  }  
  22.       
  23. //   public void run() {  
  24. //       timer.add(Thread.currentThread().getName());  
  25. //            try {  
  26. //                Thread.sleep(1000);//爲了顯示結果,讓其睡眠一秒  
  27. //            } catch (InterruptedException ex) {  
  28. //                Logger.getLogger(TestSync.class.getName()).log(Level.SEVERE, null, ex);  
  29. //            }  
  30. //          System.out.println(Thread.currentThread().getName() + "----");  
  31. //        }  
  32.       
  33.      public void run() {  
  34.            synchronized(timer){  
  35.                 timer.add(Thread.currentThread().getName());  
  36.                 try {  
  37.                     Thread.sleep(3000);  
  38.                 } catch (InterruptedException ex) {  
  39.                     Logger.getLogger(TestSync.class.getName()).log(Level.SEVERE, null, ex);  
  40.                 }  
  41.               System.out.println(Thread.currentThread().getName() + "----");  
  42.             }  
  43.         }  
  44. }  
  45.   
  46. class Timer {  
  47.     private static int num = 0;  
  48.   
  49. //  public void add(String name) {  
  50. //  
  51. //      num++;  
  52. //      try {  
  53. //          Thread.sleep(1000);  
  54. //      } catch (InterruptedException e) {  
  55. //      }  
  56. //      System.out.println(name + ", 你是第" + num + "個使用timer的線程");  
  57. //  
  58. //  }  
  59.       
  60.     public void add(String name) {  
  61.         synchronized (this) {// 同步  
  62.             num++;  
  63.             try {  
  64.                 Thread.sleep(1000);  
  65.             } catch (InterruptedException e) {  
  66.             }  
  67.             System.out.println(name + ", 你是第" + num + "個使用timer的線程");  
  68.         }  
  69.     }  
  70.       
  71.       
  72. }  
相關文章
相關標籤/搜索