程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> JAVA綜合教程 >> Java synchronized關鍵字用法(清晰易懂),synchronized關鍵字

Java synchronized關鍵字用法(清晰易懂),synchronized關鍵字

編輯:JAVA綜合教程

Java synchronized關鍵字用法(清晰易懂),synchronized關鍵字


本篇隨筆主要介紹 java 中 synchronized 關鍵字常用法,主要有以下四個方面:

  1、實例方法同步

  2、靜態方法同步

  3、實例方法中同步塊

  4、靜態方法中同步塊

  

  我覺得在學習synchronized關鍵字之前,我們首先需要知道以下一點:Java 中每個實例對象對應一把鎖且每個實例對象只有一把鎖,synchronized 關鍵字是通過對相應的實例對象加鎖來實現同步功能的。

  

  一、實例方法中使用 synchronized 加鎖

  實例方法中默認被加鎖的對象是調用此方法的實例對象。

  

 1 class ImmutableValue {
 2     public synchronized void comeIn() throws InterruptedException{
 3         System.out.println(Thread.currentThread().getName() + ": start");
 4         Thread.sleep(5000);
 5         System.out.println(Thread.currentThread().getName() + ": finish");
 6     }
 7     public  void synchronized comeInIn() throws InterruptedException {
 8         System.out.println(Thread.currentThread().getName() + ": start");
 9         Thread.sleep(5000);
10         System.out.println(Thread.currentThread().getName() + ": finish");
11     }
12 }
13 public class TestImmutableValue {
14     public static void main(String[] args) {
15         ImmutableValue im = new ImmutableValue();
16         Thread t1 = new Thread(new Runnable() {
17 
18             @Override
19             public void run() {
20                 // TODO Auto-generated method stub
21                 try {
22                     im.comeIn();
23                 } catch (InterruptedException e) {
24                     // TODO Auto-generated catch block
25                     e.printStackTrace();
26                 }
27             }
28             
29         }, "t1");
30         Thread t2 = new Thread(new Runnable() {
31 
32             @Override
33             public void run() {
34                 // TODO Auto-generated method stub
35                 try {
36                     im.comeInIn();
37                 } catch (InterruptedException e) {
38                     // TODO Auto-generated catch block
39                     e.printStackTrace();
40                 }
41             }
42             
43         }, "t2");
44         t1.start();
45         t2.start();
46     }
47 }

 

    在上面的代碼中創建了兩個線程並分別命名為 t1, t2。調用了同一個對象 im 的兩個同步方法 comeIn 和 comeInIn, 執行結果如下:

      

    在 t1 線程開始執行後,即使 t1 線程睡眠了5s,線程 t2 中的 comeInIn 方法仍然沒有得到執行。這是因為 t1 線程先執行的 comeIn 方法,持有了對象 im 的鎖,且 comeIn 方法並沒有執行完,對象 im 的鎖沒有被釋放,所以 comeInIn 方法無法對對象 im 加鎖,就無法繼續執行,只能等到 t1 線程中的 comeIn 方法執行完畢,釋放對象 im 的鎖,comeInIn 方法才能繼續執行。

    但是如果 t1 線程調用的是對象 im 的 comeIn 方法,而 t2 線程調用的是我們聲明的另外一個  ImmutableValue 對象 im2 對象的 comeInIn 方法,則這兩個方法的執行是互不影響的。因為 t1 線程的 comeIn 方法要獲得 im 對象的鎖,而 t2 線程要獲得的是 im2 對象的鎖,兩個鎖並不是同一個鎖(Java中每個實例對象都有且只有一個鎖),所以這兩個方法執行互不影響。

    

  二、靜態方法中使用 synchronized 加鎖

  靜態方法中默認被加鎖的對象是此靜態方法所在類的 class 對象。

  

 1 class staticMethodSynchronized {
 2     public static synchronized void method1() throws InterruptedException {
 3         System.out.println(Thread.currentThread().getName() + ": start");
 4         Thread.sleep(5000);
 5         System.out.println(Thread.currentThread().getName() + ": finish");
 6     }
 7     public static synchronized void method2() throws InterruptedException {
 8         System.out.println(Thread.currentThread().getName() + ": start");
 9         Thread.sleep(5000);
10         System.out.println(Thread.currentThread().getName() + ": finish");
11     }
12 }
13 public class TestStaticClassSynchronized {
14     public static void main(String[] args) {
15         Thread t1 = new Thread(new Runnable() {
16 
17             @Override
18             public void run() {
19                 // TODO Auto-generated method stub
20                 try {
21                     staticMethodSynchronized.method1();
22                 } catch (InterruptedException e) {
23                     // TODO Auto-generated catch block
24                     e.printStackTrace();
25                 }
26             }
27             
28         }, "t1");
29         Thread t2 = new Thread(new Runnable() {
30 
31             @Override
32             public void run() {
33                 // TODO Auto-generated method stub
34                 try {
35                     staticMethodSynchronized.method2();
36                 } catch (InterruptedException e) {
37                     // TODO Auto-generated catch block
38                     e.printStackTrace();
39                 }
40             }
41             
42         }, "t2");
43         t1.start();
44         t2.start();
45     }
46 }

 

    在上述代碼中創建了兩個線程並命名為 t1,t2。 t1,t2 線程調用了 staticMethodSynchronized 類的兩個靜態同步方法 method1 和 method2。執行結果如下:

    

    在 t1 線程開始執行後,即使 t1 線程睡眠了5s,線程 t2 中的 method2 方法仍然沒有得到執行。這是因為 t1 線程先執行的 method1 方法,持有了staticMethodSynchronized 類對象的鎖,且 method1 方法並沒有執行完,staticMethodSynchronized 類對象的鎖沒有被釋放,所以 comeInIn 方法無法對staticMethodSynchronized 類對象加鎖,就無法繼續執行,只能等到 t1 線程中的 method1 方法執行完畢,釋放 staticMethodSynchronized 類對象的鎖,method2 方法才能繼續執行。

 

  三、實例方法中使用 synchronized 關鍵字制造同步塊

  同步塊中默認被加鎖的對象是此同步塊括號聲明中包含的對象。

  

 1 class ImmutableValue {
 2     public synchronized void comeIn() throws InterruptedException{
 3         System.out.println(Thread.currentThread().getName() + ": start");
 4         Thread.sleep(5000);
 5         System.out.println(Thread.currentThread().getName() + ": finish");
 6     }
 7     public void comeInIn() throws InterruptedException {
 8         System.out.println(Thread.currentThread().getName() + ": start");
 9         synchronized(this) {
10             
11         }
12         System.out.println(Thread.currentThread().getName() + ": finish");
13     }
14 }
15 public class TestImmutableValue {
16     public static void main(String[] args) {
17         ImmutableValue im = new ImmutableValue();
18         Thread t1 = new Thread(new Runnable() {
19 
20             @Override
21             public void run() {
22                 // TODO Auto-generated method stub
23                 try {
24                     im.comeIn();
25                 } catch (InterruptedException e) {
26                     // TODO Auto-generated catch block
27                     e.printStackTrace();
28                 }
29             }
30             
31         }, "t1");
32         Thread t2 = new Thread(new Runnable() {
33 
34             @Override
35             public void run() {
36                 // TODO Auto-generated method stub
37                 try {
38                     im.comeInIn();
39                 } catch (InterruptedException e) {
40                     // TODO Auto-generated catch block
41                     e.printStackTrace();
42                 }
43             }
44             
45         }, "t2");
46         t1.start();
47         t2.start();
48     }
49 }

 

    由以上代碼可以看到: 在 comeInIn 方法中,運用  synchronized(this) 制造同步塊,要執行同步塊內的代碼,就必須獲得 this 對象的鎖(調用 comeInIn 方法的對象)。

    執行結果可能為:

    

    由此執行結果可見:t1 線程先執行了 comeIn 方法,獲得了對象 im 的鎖,之後由於 t1 線程進入睡眠狀態,t2 線程得到運行,開始執行 comeInIn 方法,當執行到同步代碼塊時發現對象 im 已被加鎖,無法繼續執行。t1 線程睡眠結束之後繼續執行,結束後釋放對象 im 的鎖,t2 線程才能繼續執行。

 

  四、靜態方法中使用 synchronized 關鍵字制造同步塊

  同步塊中默認被加鎖的對象是此同步塊括號聲明中包含的對象。

  

 1 class staticMethodSynchronized {
 2     private static final Object OBJ = new Object();
 3     public static void method1() throws InterruptedException {
 4         System.out.println(Thread.currentThread().getName() + ": start");
 5         synchronized(OBJ) {
 6             System.out.println(Thread.currentThread().getName() + ": 獲得鎖");
 7             System.out.println(Thread.currentThread().getName() + ": 釋放鎖");
 8         }
 9         System.out.println(Thread.currentThread().getName() + ": finish");
10     }
11     public static void method2() throws InterruptedException {
12         System.out.println(Thread.currentThread().getName() + ": start");
13         synchronized(OBJ) {
14             System.out.println(Thread.currentThread().getName() + ": 獲得鎖");
15             System.out.println(Thread.currentThread().getName() + ": 釋放鎖");
16         }
17         System.out.println(Thread.currentThread().getName() + ": finish");
18     }
19 }
20 public class TestStaticClassSynchronized {
21     public static void main(String[] args) {
22         Thread t1 = new Thread(new Runnable() {
23 
24             @Override
25             public void run() {
26                 // TODO Auto-generated method stub
27                 try {
28                     staticMethodSynchronized.method1();
29                 } catch (InterruptedException e) {
30                     // TODO Auto-generated catch block
31                     e.printStackTrace();
32                 }
33             }
34             
35         }, "t1");
36         Thread t2 = new Thread(new Runnable() {
37 
38             @Override
39             public void run() {
40                 // TODO Auto-generated method stub
41                 try {
42                     staticMethodSynchronized.method2();
43                 } catch (InterruptedException e) {
44                     // TODO Auto-generated catch block
45                     e.printStackTrace();
46                 }
47             }
48             
49         }, "t2");
50         t1.start();
51         t2.start();
52     }
53 }

 

    在上述代碼中,兩個靜態方法中的同步塊都要獲得對象 OBJ 的鎖才能繼續向下執行,執行結果可能如下:

       

    若 t1 線程先獲得鎖,則必須等到 t1 釋放鎖之後,t2 線程中同步代碼塊及其之後的代碼才能繼續執行,t2 線程先獲得鎖,t1 線程同理。

 

   總之,我認為我們只需抓住一點:Java 中每個實例對象對應一把鎖且每個實例對象只有一把鎖,synchronized 關鍵字是通過對相應的實例對象加鎖來實現同步功能的(靜態方法為對相應的 class 對象加鎖)。在執行 synchronized 方法或 synchronized 同步塊之前,我們只需判斷其需要獲得的對象的鎖是否可獲得,就可判斷此方法或同步塊是否可得到執行。

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