簡體   English   中英

靜態同步方法和非同步靜態方法混淆

[英]Static synchronized methods and non-synchronized static methods confusion

我有一點困惑。 請看下面的代碼。

public class ThreadDemo {
  //non-static synchronized method
  synchronized void a(){
   actBusy();
  }

  //static synchronized method
  static synchronized void b(){
    actBusy();
  }

  //static method
  static void actBusy(){
    try{
      Thread.sleep(1000);
    }
    catch(InterruptedException e) {
      e.printStackTrace();
    }
  }

  public static void main(String[] args){
    final ThreadDemo x = new ThreadDemo();
    final ThreadDemo y = new ThreadDemo();
    Runnable runnable = new Runnable() {
      public void run() {
         int option = (int) (Math.random() * 4);
         switch (option){
           case 0: x.a();
             break;
           case 1: x.b();
             break;
           case 2: y.b();
             break;
           case 3: y.b();
             break;
         }
      }
    }   ;
    Thread t1 = new Thread(runnable);
    Thread t2 = new Thread(runnable);
    t1.start();
    t2.start();
  }
}

我確信可以調用這個序列。

x.a() //in Thread-1
y.b() //in Thread-2

雖然我仍然有一點混亂,但我們可以很容易地看到xa()也調用actBusy()方法,這是一種靜態方法。 方法b()是一個調用非同步靜態方法的靜態同步方法。 當thread-2獲得類級別鎖定時,為什么不阻止來自Thread-1的actBusy()調用?

我只是在邏輯上混淆,如果一個線程獲得類級別鎖定,該類其他非同步靜態方法保持打開以從其他方法(實例方法)調用。 為什么?

為什么不阻止從Thread-1調用actBusy()

由於您的actBusy方法未同步。 即使您獲得了類級別鎖定,也可以調用非同步靜態方法。

將方法標記為已synchronized是啟用鎖定。 只有聲明為synchronized的方法才是這些鎖的主題。 因此,如果您獲得了一個鎖(假設類級別鎖定),則任何non-synchronized方法都會像以前一樣起作用,並且不知道正在獲取鎖定。 這允許您決定哪些方法需要阻止,哪些方法不需要。

static synchronized方法對類對象有一個鎖,而非靜態synchronized方法對實例對象有一個鎖( this ) - 所以兩個方法可以同時調用,一個線程運行1而另一個運行第二個。

但請注意,您的代碼中沒有可用的競爭條件 ,因為競爭條件需要寫入,這些方法中不存在這種情況。

actBusy()本身不是同步的,但調用方法是。

因此,線程1不會阻塞,因為它獲取this對象的鎖定,並且沒有其他線程this持有鎖定,因此它可以毫無問題地調用它。

這是因為non-static synchronized上方法鎖this本實例而不是class對象。

xa()獲取當前實例的鎖,即x並且沒有其他線程能夠輸入x方法a() ,直到當前線程釋放鎖。

線程1 - > xa() //acquires lock and holds it

線程2 ---> xa() //blocks here until Thread 1 releases lock on x

編輯:

Class Object != Instance 

因此根據JMM,它們是不同的對象,並且兩個線程不會相互干擾。 所以它允許你調用它。

編輯2:

為什么它允許調用其他靜態方法? 它背后的任何邏輯?

假設這個:

public static synchronized int statefulMethod(){
    //this should be protected
}

public static int nonStatefulMethod(){
    //Just returns a static value such as 5
    //so this is thread safe as it does not have any state
}

public static synchronized int otherStatefulMethod(){
    //this should also be thread safe
}

因此,如果線程1在方法statefulMethod()中有一些共享狀態要保護,那么它使用類級別鎖定。 現在線程2調用nonStatefulMethod()然后它不應該邏輯阻塞,因為該方法是線程安全的,並且沒有必要在此處進行該線程阻塞

現在,如果線程3調用otherStatefulMethod()而線程1持有類鎖,那么線程3必須等待,因為該方法也是static-synchornized

鎖定對象不是分層的。 因此,獲取類本身的鎖定並不會取代對類實例的鎖定。 它們是單獨的鎖定對象,只會阻止嘗試鎖定同一對象的代碼。

因此,如果一個線程進入靜態同步方法,那么唯一將被阻塞的線程也是那些試圖在同一個類上輸入靜態同步方法的線程。 僅僅嘗試進入非靜態同步方法的線程不受影響 - 它們僅與試圖在同一對象實例上輸入非靜態同步方法的線程競爭。

關於下面的注釋 - 只有標記為synchronized靜態方法才會受到類級鎖定的影響。 如果要阻止其他靜態方法,還必須將它們標記為已synchronized

為什么會這樣? 好吧,編譯器假設您需要鎖定所有靜態方法只是因為一個被標記為已synchronized ,這是相當冒昧的。 假設程序員知道必須同步哪些方法以確保線程安全。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM