2013-03-15 48 views
77

如果我在同一個類上同步兩個方法,他們可以同時在同一個對象上運行?例如:如果我在同一個類上同步兩個方法,它們可以同時運行嗎?

class A { 
    public synchronized void methodA() { 
     //method A 
    } 

    public synchronized void methodB() { 
     // method B 
    } 
} 

我知道,我不能在兩個不同的線程同一對象上運行methodA()兩次。同樣的東西在methodB()

但是我可以在不同的線程上運行methodB()methodA()仍在運行? (同一對象)

回答

85

兩種方法都鎖定相同的監視器。因此,你不能同時在不同線程的同一個對象上執行它們(兩個方法中的一個會阻塞,直到另一個完成)。

+0

我對這個問題有一個補充。假設兩個方法都是靜態的,現在使用Class來調用methodA,而使用對象調用methodB,如t1中的A.methodA()和t2中的obj.methodB()。現在會發生什麼,他們會阻止? – amod 2013-03-21 12:16:45

+1

@ amod0017:'當methodB()'爲'static'時,'obj.methodB()'與'A.methodB()'是同義的。因此是的,他們會阻止(在課堂上,而不是對象的顯示器上)。 – NPE 2013-03-21 12:21:07

+0

將盡力回覆它。 :) – amod 2013-03-21 14:34:01

0

您正在同步它不在課堂上的對象。所以,他們不能對同一對象

62

上的方法把​​上同時運行意味着線程進入該方法之前收購的對象實例的鎖,所以如果你有兩種不同的方法,標誌着同步線程進入他們的將是爭奪相同的鎖,並且一旦一個線程獲得鎖,所有其他線程將被關閉在所有同步鎖上同步的方法中。因此,爲了使這兩種方法同時運行,他們將不得不使用不同的鎖,就像這樣:

當它進入一個 實例同步Java方法
class A { 
    private final Object lockA = new Object(); 
    private final Object lockB = new Object(); 

    public void methodA() { 
     synchronized(lockA) { 
      //method A 
     } 
    } 

    public void methodB() { 
     synchronized(lockB) { 
      //method B 
     } 
    } 
} 
+0

,所以在這個例子中,鎖在lockA \ lockB對象上,而不在類A上? 這是一個_class級鎖定示例嗎? – Nimrod 2016-07-21 07:19:36

+1

@Nimrod:它鎖定在lockA和lockB對象上,而不是在A的實例上。這裏沒有任何東西鎖定在類上。類級別鎖定意味着使用類似'static synchronized'或'synchronized(A.class)'的方法來獲取類對象的鎖定。[ – 2016-07-21 12:22:11

+0

]這裏是[link](https://docs.oracle.com/javase/) tutorial/essential/concurrency/locksync.html)到java教程解釋到底是什麼答案。 – 2016-11-09 17:46:17

12

Java線程獲取到一個對象級鎖並獲取級鎖進入時靜態同步java方法。

在你的情況下,方法(實例)是相同的類。所以當一個線程進入java synchronized方法或阻塞時,它會獲得一個鎖(調用該方法的對象)。所以其他方法不能同時在同一個對象上被調用,直到第一個方法完成並且鎖定(在對象上)被釋放。

6

在你的情況下,你在同一個類的實例上同步了兩個方法。因此,這兩種方法不能同時在同一個A類實例的不同線程上運行,但它們可以在不同的A類實例上運行。

class A { 
    public synchronized void methodA() { 
     //method A 
    } 
} 

相同:

class A { 
    public void methodA() { 
     synchronized(this){ 
      // code of method A 
     } 
    } 
} 
3

只是爲了所有清楚起見,這是可能的,這兩個靜態同步和因爲一個是具有對象級鎖和其它類非靜態同步方法可以同時或併發地運行級鎖。

3

從Oracle的文檔link

同步製作方法有兩個作用:

首先,它是不可能的同一對象上同步方法來交錯兩個調用。當一個線程正在執行一個對象的同步方法時,所有其他線程調用同一對象的同步方法塊(掛起執行),直到第一個線程完成對象。其次,當一個同步方法退出時,它會自動建立一個與先前關聯的同步對象的任何後續調用同步方法。這保證了更改對象的狀態是可見的所有線程

這將會回答你的問題:在同一個對象,你不能叫第二同步方法時,第一個synchronized方法執行過程中。

查看此文檔page以瞭解內部鎖和鎖定行爲。

-2

兩個不同的線程在單個對象上執行公共同步方法,因爲對象是相同的,當一個線程在同步方法中使用它時,它將不得不變更鎖定,如果啓用了鎖定,該線程將會去等待狀態,如果鎖定被禁用,則它可以訪問該對象,而它將訪問該對象將啓用鎖定,並且只有在其執行完成時纔會釋放鎖定 。 當另一個線程到達時,它會變化鎖,因爲它被啓用,它將等待,直到第一個線程完成其執行並釋放放置在該對象上的鎖,一旦鎖釋放,第二個線程將獲得對該對象的訪問權它會啓用鎖定直到執行。 所以執行不會是併發的,兩個線程都會逐個執行,當兩個線程對不同的對象使用synchronized方法時,它們將同時運行。

+0

請仔細標註和大寫這個混亂。沒有像'varify'這樣的詞。 – EJP 2018-01-05 02:45:18

2

覺得你的代碼爲以下之一:

class A { 

public void methodA() { 
    synchronized(this){   
     //method A body 
    } 
} 

public void methodB() { 
    synchronized(this){ 
     // method B body 
    } 
} 

因此,在方法層面同步僅僅意味着同步(這一點)。 如果任何線程運行此類的方法,它將在開始執行之前獲取鎖定並保持該方法直到方法執行完成。

但我可以在不同的線程上運行methodB(),而methodA()仍然運行在 ? (相同的對象)

確實,這是不可能的!

因此,多個線程將無法同時在同一對象上運行任何數量的同步方法。

相關問題