簡體   English   中英

Java同步塊

[英]Java synchronized blocks

如果我們有一個方法:

public void doSomething(){
    synchronized(this){
        //some code processing here
    }
    String temp = "init"; //instead of i++
    synchronized(this){
        //some other code processing here
    }
}

這個方法是否等同於public synchronized void doSomething()

是否有任何理由假設某些執行中的線程調度程序不會導致與同步整個函數有效的流程相同? 那是:

  • Thread1進入第一個同步塊。
  • Thread2塊。
  • Thread1繼續使用i++並移動到第二個同步塊,而Thread2仍然被阻塞。
  • 其結果是, 線程2進入后線程1已經退出都同步塊中的方法。

我需要知道的是:

  • 我能指望所有執行上下文這兩個線程( 線程1線程 ),能夠同時在方法? 例如, 線程2在第二同步塊中的第一同步塊和線程1實現的並發性。
  • 是否會有一些執行流程,其中只有一個線程將在該方法中(一次)有效地序列化整個流程,使其等效於public synchronized void doSomething()

某些執行中,它將具有與同步整個函數相同的流程,當然 - 但是為了使其真正等同於使方法同步,它必須為所有執行具有相同的流程。

實際上,另一個線程有可能在執行過程中獲取鎖定(無論是對於此方法還是在同一監視器上的其他代碼鎖定)。 如果方法本身是同步的,則不會發生這種情況,因此它們不相同。

(順便說一句,鎖定在this被普遍認為是不好的做法,無論如何,我不記得上一次我寫了一個synchronized方法我鎖定在私人持有的顯示器代替,讓我知道我的代碼是唯一代碼。可以鎖定它們。)

編輯:回復您的編輯:

我需要知道的是,我是否可以依賴所有執行上下文,兩個線程(例如Thread1和Thread2)可以同時在方法中,例如第一個同步塊中的thread2和第二個同步塊中的thread1以實現並發

絕對不! 保證在同一監視器上同步的同步塊中不會有兩個線程。

您有三個代碼段:第一個同步塊,未同步部分和第二個同步部分。

一次可以在非同步部分中執行任意數量的線程。 對於任何一個實例(因為你上同步this )只有一個線程可以執行兩種同步塊。 如果要實現並發,則必須在不同的監視器上進行同步。

此外,聽起來你想要保證調度程序讓另一個線程在等待它時抓住鎖。 我不相信有任何這樣的保證 - 執行第一個塊的線程可以釋放鎖定但繼續在相同的時間片中並在任何其他線程進入之前重新獲取它。在一些可能不會發生的JVM中,但我不知道相信周圍有任何保證。

不,這不對。 例如,對於上面的代碼

線程1進入第一個同步塊執行它然后退出然后被切換出來。 線程2進入第一個同步塊執行增量,然后在切換之前進入第二個同步塊。 線程1現在無法繼續,直到線程2退出第二個同步塊。

如果整個方法是同步的,則不會發生這種模式。

我需要知道的是,我是否可以依賴所有執行上下文,兩個線程(例如Thread1和Thread2)可以同時在方法中,例如第一個同步塊中的thread2和第二個同步塊中的thread1以實現並發

沒有! 情況永遠不會如此。 只有一個鎖與this相關聯。 借助於使用相同的鎖都同步塊,這是不可能的線程2是在第一synchronized塊,如果線程1處於第二synchronized塊。

所有其他答案表明您發布的方法與同步整個方法的方法在技術上是正確的。

鑒於synchronized關鍵字用於在Java中實現監視器,因此無法保證給定的代碼片段是同步的。

實際上,所討論的兩個線程是否有可能完成第一個同步塊,然后在執行下一個塊之前執行該語句以增加i的值。

我假設變量i包含兩個線程之間共享的狀態,在這種情況下操作不是線程安全的。 為了使操作序列成為線程安全的,您必須確保整個序列一次由一個線程執行。 在單獨的監視器中執行各個操作與在沒有監視器的情況下執行操作一樣好; 整個序列必須由監視器保護。

有關詳細信息,請參閱artima.com,內容來自Java虛擬機內部

編輯

鑒於問題現在反映了本地String對象的使用,操作序列可以被視為線程安全。 每個線程在堆棧上為String對象創建自己的本地引用; 由於String對象的不可變屬性,一個線程中對象的任何變異都不會影響另一個(為了所有實際目的創建一個新的String對象,當發生變異時,因此狀態不是真正在線程之間共享)。

重點

在嘗試線程同步時,如果對共享數據的訪問是互斥的,則將操作序列視為線程安全的; 這樣,一個線程將無法讀取或寫入共享變量,而另一個線程正在執行涉及共享數據的操作。 僅使用局部變量,消除了線程之間的任何共享感。

不,它不等於synchronized void doSomething()因為i++不是原子操作。 事實上,它可能會像

int temp = i; i = i + 1; result = temp

如果這些操作不是原子的,那么當它處於錯誤狀態時,可以讀取i的值。

此方法與使其成為同步方法不同。 您可能會看到您解釋的行為,但永遠不能保證。

暫無
暫無

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

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