2010-07-01 169 views
31

我有4種方法(m1,m2,m3m4)在一個類中。方法m1,m2m3是​​方法。另外,我有4個線程分別爲t1t2,t3t4同時執行兩個同步方法

如果t1接入m1方法(同步方式),可以t2線程訪問m2方法同時(同步方法)?如果不是什麼狀態的t2?

回答

42

如果t1訪問m1方法(同步方法),可能t2線程同時訪問m2方法(同步方法)嗎?

的​​關鍵字適用於對象級別,只有一個線程可持有對象的鎖。所以只要你在談論同一個對象,那麼t2將等待t1釋放當它進入m1時獲得的鎖定。

但是,線程可以通過調用Object.wait()來釋放鎖而無需從方法返回。

如果不是,那麼t2的狀態是什麼?

這將穩坐,等待t1(從方法返回或調用Object.wait())解除鎖定。具體來說,它將在BLOCKED state

線程阻塞等待監視器鎖定的線程狀態。處於阻塞狀態的線程正在等待監視器鎖定,以便在調用Object.wait之後輸入同步塊/方法或重新輸入同步塊/方法。

樣品的編號:

public class Test { 

    public synchronized void m1() { 
     try { Thread.sleep(2000); } 
     catch (InterruptedException ie) {} 
    } 

    public synchronized void m2() { 
     try { Thread.sleep(2000); } 
     catch (InterruptedException ie) {} 
    } 

    public static void main(String[] args) throws InterruptedException { 
     final Test t = new Test(); 
     Thread t1 = new Thread() { public void run() { t.m1(); } }; 
     Thread t2 = new Thread() { public void run() { t.m2(); } }; 

     t1.start(); 
     Thread.sleep(500); 

     t2.start(); 
     Thread.sleep(500); 

     System.out.println(t2.getState()); 
    } 
} 

輸出:

BLOCKED 
+0

但是如果我們做這樣的事情,那又怎樣? final Test tt1 = new Test(); final Test tt2 = new Test();線程t1 = new Thread(){public void run(){tt1.m1(); }};線程t2 = new Thread(){public void run(){tt2.m2(); }}; – Prem 2012-04-10 09:17:50

+0

我運行同樣的東西,我得到TIMED_WAIT作爲輸出.... – Prem 2012-04-10 09:18:12

+0

@aioobe在同步代碼塊(而不是方法)的情況下會發生什麼。兩個線程可以同時訪問同一對象的兩個不同的同步代碼塊嗎? – yuva 2014-09-18 11:48:15

11

如果方法在同一監視器上同步,則它們不能同時在不同的線程中執行。當第二個線程進入監視器條目(這種情況下,同步方法的開始)時,它將阻塞,直到第一個線程釋放監視器。

在這種情況下,被阻塞的線程的實際狀態,所報告的JConsole的,將是這樣的java.lang.Thread.State: WAITING (on object monitor)

假設所有的方法都是正常的實例方法,那麼他們將共享相同的顯示器在同一調用時對象。也就是說,如果你有這樣的事情:

// Thread 1 
A a1 = new A(); 
a1.m1(); 

// Thread 2 
A a2 = new A(); 
a2.m2() 

那麼在這種情況下,第二個線程就可以調用該方法,因爲它試圖獲取a2對象,這是的隱式監視器由線程1鎖定。但是,如果線程2試圖呼叫a1.m2(),那麼它將阻塞,直到線程1完成執行m1()

如果你有靜態方法,那麼他們獲得的類本身的(A.class在我假想命名的情況下)顯式顯示器,所以不會受到任何例如方法調用被阻止。

+0

實際上,它將處於BLOCKED狀態,而不是WAITING狀態。 – aioobe 2010-07-01 17:19:19

+0

在上面的例子中調用'a2.m2()'有點令人誤解。由於'a1'和'a2'是類'A'的不同實例,每個都有自己的'lock'。因此,即使'a1.m1()'和'a2.m1()'也可以同時執行。 – derenio 2015-11-25 10:24:08

+0

@derenio - 那是我在該部分所做的全部觀點,根據之前的粗體陳述。因爲問題是問是否可以立即調用'm1'和'm2',這就是我在示例中堅持的內容。 – 2015-11-25 10:31:06

4

不,它不能。這是​​唯一的一點:不同的線程不能同時做這些事情(你不必同時做同一個線程,因爲一個線程根本無法並行執行任何操作)。等待線程的狀態是'等待鎖定'。 (有足夠的現代JVM你其實可以有控制檯上顯示這種狀態下,如果你以正確的方式問。)

1

如果T1接入M1方法(synchronized方法),可以t2的線程訪問M2方法(同步方法)同時?

否。線程t2將等待線程t1釋放鎖。 在你的同一個例子中,t2可以訪問未同步的方法m4。

鎖在synchronized方法

每個對象都有一個與之關聯的內部鎖。按照慣例,需要獨佔且一致地訪問對象字段的線程在訪問它們之前必須獲取對象的內部鎖,然後在完成對象的內部鎖之後釋放固有鎖

當線程調用同步方法時,自動獲取該方法對象的內部鎖並在方法返回時釋放它。鎖定解除即使返回被一個未捕獲的異常

回來到您的第二個查詢導致發生:

如果不是這樣,這將是T2的狀態?

線程t2處於阻塞狀態並等待線程t1釋放鎖。

從Java documentation頁:

使​​方法有兩個作用。

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