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

来源:http://www.cnblogs.com/Michaelwjw/archive/2016/10/06/5933687.html
-Advertisement-
Play Games

本篇隨筆主要介紹 java 中 synchronized 關鍵字常用法,主要有以下四個方面: 1、實例方法同步 2、靜態方法同步 3、實例方法中同步塊 4、靜態方法中同步塊 我覺得在學習synchronized關鍵字之前,我們首先需要知道以下一點:Java 中每個實例對象對應一把鎖且每個實例對象只有 ...


本篇隨筆主要介紹 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 同步塊之前,我們只需判斷其需要獲得的對象的鎖是否可獲得,就可判斷此方法或同步塊是否可得到執行。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 批處理是一次性向資料庫發出多條查詢指令,一起執行Statement 介面定義的方法:|—增加批處理語句: |—執行批處理: PreparedStatement介面定義的方法:增加批處理:public void addBatche()throws SQLexceeption public class ...
  • 下麵是我今天下午用PHP寫的一個生成圖片驗證碼demo,僅供參考。這個demo總共分為4個文件,具體代碼如下: ...
  • 題目鏈接 https://acm.bnu.edu.cn/v3/contest_show.php?cid=8506#problem/A problem description As we know, the NTU Final PK contest usually tends to be pretty ...
  • (-1)寫在前面 spring2.0、struts1.2、hibernate3.0、myeclipse8.5、tomcat6.0,整合之中出現了很多問題,前幾天忙著整理畢業論文的資料,時間騰出來了,總算有能寫的東西。話說這宿舍的人少了,蚊子的選擇也少了。 (0)詳細解釋 a.錯誤產生的原因 java ...
  • 要用Java實現記事本的功能。首先列出記事本所需功能: 可以添加記錄(字元串); 可以獲得記錄條數; 可以刪除其中某一條記錄; 可以獲得指定第幾條的記錄; 可以列出所有的記錄。 如果這個記事本是某個大程式的其中一部分,也就是說還有上層程式,那麼上層程式就有可能會調用這個記事本以上列出的某個數據。 ... ...
  • 一、記憶體中的程式: 在進程被載入記憶體中時,基本上被分成許多小的節,以下是6個主要的節。 低地址 高地址 .text 節 .text節基本上相當於二進位可執行文件的.text部分,它包含了完成程式任務的機器指令。 該節標記為只讀,如果發生寫操作,會造成 segmentation fault。 在進程最 ...
  • 靜態代理 1、新建一個介面,這個介面所提供的方法是關於資料庫操作的 2、建一個目標類實現這個介面,這個目標類是我們要進行的業務 3、再建一個代理類,為目標對象提供一種代理,並以控制對這個對象的訪問。 由以上可知,代理模式的組成包括:目標介面(抽象角色),目標類(真實角色)和代理類(代理角色)。 4、 ...
  • Atitit 判斷判斷一張圖片是否包含另一張小圖片 1. keyword1 2. 模板匹配是在圖像中尋找目標的方法之一(切割+圖像相似度計算)1 3. 匹配效果2 4. 圖片相似度的演算法(感知哈希演算法”(Perceptual hash algorithm)2 5. 性能結果2 6. 如何提升性能3 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...