2016-07-05 117 views
2

爲了正確理解Java中的併發問題和解決方案,我正在閱讀官方的Java教程。在他們定義的頁面之一內部鎖和同步link。在這個頁面上,他們說:內部鎖實際上對Java類意味着什麼?

只要一個線程擁有一個內部鎖,其他線程就不會獲得相同的鎖。當其他線程嘗試 獲取鎖時將阻塞。

另外,它們在部分提鎖在同步方法在於:

當一個線程調用一個同步方法,它自動獲取 用於該方法的對象並釋放它時,內部鎖方法返回 。即使返回由未捕獲的異常導致 ,也會發生鎖定釋放。

對我來說,這意味着一旦我稱之爲同步方法從一個線程,我將有螺紋的內部鎖的保持,因爲

內在鎖起到兩個方面的作用的同步: 強制對對象的狀態進行獨佔訪問並建立 發生在對可見性至關重要的關係之前。

會另一個線程無法調用同一類的另一個同步方法嗎?如果是的話,那麼同步方法的全部目的就會失敗。不是嗎?

+0

您的問題不明確。當您詢問「我*無法再調用另一種同步方法...」時,「我」是指什麼?根據線程構建您的問題。你問是否同一個線程可以從同步方法調用同步方法?也就是說,Java固有鎖重入嗎?還是你質疑互斥體的效用? – erickson

+0

內在方法意味着您不必創建一個對象來同步您的方法。相比之下,你可以通過調用'synchronized(myLock){...}'來使用外部鎖。這是實踐中Java併發性的一個摘錄:「每個對象都有內置鎖的事實只是一種方便,因此您不需要明確創建鎖對象」 –

+0

我剛剛更新了問題,以便明確提到的含糊問題由@erickson .. – Swapnil

回答

2

所以只是重複我的評論作爲一個答案。內部鎖定意味着您不必創建一個對象來同步您的方法。相比之下,您可以通過調用synchronized(myLock) {...}來使用外部鎖。

這是一本書Java concurrency in practice的摘錄:「每個對象都有一個內置的鎖時,這只是一個方便,讓你不必明確創建鎖定對象」

書中還寫道:

對象的固有鎖定 與其狀態之間沒有內在聯繫;一個對象的字段不需要被內部鎖 保護,雖然這是一個完全有效的鎖定約定,許多類都使用 。獲取與對象關聯的鎖不會阻止其他線程訪問該對象, 獲取鎖的唯一方法是阻止任何其他線程執行操作,即獲取相同鎖的 。每個對象都有一個內置鎖的事實只是一個便利,因此您不需要顯式創建鎖對象。 [9] 您可以構建鎖定協議或同步策略,以便您安全地訪問共享狀態,並在整個程序中始終如一地使用它們。

但在腳註它說:

[9]回想起來,這樣的設計決策可能是一個壞的:不僅 可以說,它是混亂的,但它迫使JVM實現者做出 對象大小和鎖定性能之間的折衷。

並回答最後一個問題:您將無法從另一個線程調用synchronized方法,但可以繼續從同一個線程進入(內部鎖可重入)。所以你必須想象在這種情況下鎖定從不同的調用者線程訪問序列化方法。

如果你使用不正確的鎖定,然後引入生命危險,那麼它是失敗的。這就是爲什麼你必須確保你的併發線程不會相互爭奪太多。

由於Brian Goetz puts in this blog entry

在調優應用程序的使用同步的,那麼,我們應該儘量 努力減少實際爭的量,而不是簡單地嘗試 避免使用在所有

同步
+1

謝謝你的回答。我想我現在更清楚一點。 – Swapnil

+0

@Swapnil不客氣。快樂的編碼! –

1

是的,由於固有的鎖定,您將無法在同一對象上調用其他同步方法。在對象級別,只有一個線程會獲得它。

1

​​方法是否屬於同一個類並不重要,重要的是如果方法的調用者線程獲取鎖定或沒有獲取鎖定,那麼它將被允許進入臨界區域因爲鎖是reentrant

如果不是的話,那麼一個遞歸調用會導致死鎖,

fn(){ 
synchronized(mutex){ // the current thread has already acquired the mutex 
    fn(); 
} 
} 

FN這裏慣於僵局因爲鎖是重入,即(這已經收購可鎖的線程只要仍然獲得,就要再次輸入並出租關鍵部分)。

+0

sry,但我更新了我的問題,以便更清楚。我的問題是關於調用另一個'synchronized'方法的另一個線程。 – Swapnil

2

似乎你有一個誤解(不知道是否導致了錯誤的結論),沒有人指出。無論如何,一個簡短的回答:

內部鎖:只要認爲它,JVM中的每個對象內部都有一個鎖。​​關鍵字嘗試獲取目標對象的鎖定。每當你synchronized (a) { doSomething; },真正發生的

  1. a鎖被收購
  2. 碼同步塊內運行(doSomething
  3. 釋放鎖a

祝你知道

public synchronized void foo() { 
    doSomething; 
} 

概念一樣

public void foo() { 
    synchronized(this) { 
     doSomething; 
    } 
} 

好了,回到你的問題,最大的問題,恕我直言,是:

對我來說,這意味着一旦我稱之爲同步方法從一線程,我將有線程以來的內部鎖的持有...

這是錯誤。當你調用一個同步方法時,你是而不是得到線程的鎖

取而代之的是,線程將自己的對象是「擁有」方法的內部鎖。

例如在thread1中,您調用a.foo(),並假定foo()已同步。 thread1將獲取對象a的內在鎖定。

同樣,如果AClass.bar()被調用(並且bar是同步的並且是靜態方法),則將獲取AClass Class對象的內部鎖。

+0

因此,當我從**線程**調用同步方法並獲得**對象**的內部鎖定時,我是否可以從另一個線程調用另一個同步方法?很抱歉,我的問題中含糊不清。 – Swapnil

+0

嘗試在THAT對象上同步的另一個線程(顯式同步,調用該對象的同步方法等)需要等待。你需要清楚*它是什麼*同步的方法。如果它只是另一個不相關對象的同步方法,當然可以 –

1

我會無法調用同一類的另一個同步方法嗎?如果是的話,那麼同步方法的全部目的就會失敗。不是嗎?

號你不能要求對象級鎖同一對象的其他​​方法,你不能調用其他方法static sysnchronized對同一類。

但它並沒有打破同步的目的。

如果按照第synchronized方法的其它文檔頁:

使這些方法​​有兩個作用:

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

如果允許兩個​​方法並行運行。你一定會在共享數據上得到內存不一致的錯誤。

在另一方面,Lock提供了更好的替代​​構造。

相關SE問題:

Synchronization vs Lock

+0

謝謝你的回答和參考。雖然,你的回答足夠好,@Captain Fogetti的回答更詳細的解釋與其他有用資源的鏈接。所以,我將其標記爲正確。再次感謝。 – Swapnil

2

鎖只能由一個線程在同一時間舉行。這並不能達到目的;即的目的。

線程MUT ually CLUDE從在臨界區同時作用彼此通過獲取鎖,或互斥。這提供了圍繞一系列不同操作的有效原子性,以便其他線程永遠不會看到可能違反一致性保證的中間狀態。

0

鎖可以分爲兩類 - '可重入'和'不可重入'。 在Java'synchronized'中,接口Lock(類ReentrantLock),接口ReadWriteLock(類ReentrantReadWriteLock)的基本實現是可重入的。 重入是指 - 一個線程可以一次又一次地持有鎖。