Synchronized 你真的懂嗎?

在這裏插入圖片描述

關於 Synchronized 的原理可以參見 聊聊併發(二)Java SE1.6中的Synchronized

概念

  • 首先要強調的一點 Synchronized 並不是鎖它只是一個關鍵字,他的作用是標記方法或者代碼塊是同步的。Synchronized 關鍵字會直接鎖住公共內存,保證資源、數據的同步避免競爭。
  • 本質上 Synchronized 鎖住的是一個叫 Monitor 的東西,如果一個 Monitor 被 Synchronized 標記,所有訪問此 Monitor 的動作都會被阻塞直到 Monitor 被釋放掉。
  • 被 Synchronized 標記的代碼塊執行完畢後會自動釋放 Monitor 即解除鎖。
  • Synchronzied 是一個很重的方法。

Synchronized 大概可以分爲以下幾種同步塊:

  • 標記實例方法:實例同步方法

    在方法聲明的時候加上 Synchronized 關鍵字,這將告訴 Java 此方法是同步的,此時 Synchronized 的 Monitor 是擁有該方法的對象。所以當前線程可以訪問此類的任何實例方法, 而其他線程需要等待 methodA() 結束。

    這樣每一個 methodA() 方法都同步在不同的對象上,即該方法所屬的實例。如果有多個實例存在,那麼一個線程一次可以在一個實例同步塊中執行,即一個實例一個線程。

  public class SynchronizedDemo {  
  	/**
     * 此時 synchronized 鎖住的是當前對象!
     */
    public synchronized void methodA() {
  		……
    }
  }
  • 標記靜態方法 :靜態同步方法

    靜態方法同步和實例方法同步方法一樣,也使用synchronized 關鍵字。被 static 標記的方法也稱類方法,他是屬於類的而非具體對象,所以如果 Synchronized 方法標記了靜態方法,此時的 Monitor 將會是 SynchronizedDemo 的字節碼文件( SynchronizedDemo.class 也就是類對象),在 Java 虛擬機中一個類只有一個類對象,這意味着不管同一個類中的哪個靜態同步方法被訪問,其他的線程都需等待。即一個字節碼文件一個線程。

    對於不同類的靜態同步方法,他們的 Monitoer 爲各自的字節碼文件,所以一個線程可以同時訪問不同類中的竟然方法而無需等待。

  public class SynchronizedDemo {   
  		/**
       * staticA 的寫法等價於 staticB
       */
      public static synchronized void staticA() {
  
      }
  
      public static void staticB() {
          synchronized (SynchronizedDemo.class){
  
          }
      }
  }
  • 實例方法中標記代碼塊

      // 此方式將會鎖住當前實例
        synchronized (this) {

        }

        // 鎖住字節碼文件,意味着 SynchronizedDemo 的所有實例都會被鎖住
        synchronized (SynchronizedDemo.class) {

        }

        // 鎖住指定的實例,這種方式一般用於單獨判讀
        synchronized (monitor) {

        }
  • 靜態方法中標記代碼塊

  public class SynchronizedDemo {   
  		/**
       * staticA 、staticB 寫法等價
       */
      public static synchronized void staticA() {
  
      }
  
      public static void staticB() {
          synchronized (SynchronizedDemo.class){
  
          }
      }
  }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章