2013-02-04 63 views
1

我對Java中的多線程並不很有經驗。我想要的是設置一個代碼塊的鎖。在我的情況下,我想避免樂觀鎖定異常,同時爲某個用戶做一些同步。方法replicateUser可以由同一用戶的多個線程調用。但是不能保證,那authenticatedUser永遠是同一個對象。如何有效地鎖定代碼塊以避免樂觀鎖定異常

那麼我怎樣纔能有效地鎖定這一部分?我不想要的是,該部分對於所有線程都是鎖定的,但僅限於具有相同用戶的部分。如下例所示,我可以使用getUserName()鎖定字符串對象嗎?在authenticatedUser.getUserName().intern()

private void replicateUser(AuthenticatedUser authenticatedUser) { 
    // 
    // How to synchronize the following block correctly? 
    // 
    synchronized (authenticatedUser.getUserName()) { 
     User dbUser = userRepository.findOne(authenticatedUser.getUserName()); 
     if (!checkIsUserReplicated(authenticatedUser, dbUser)) { 
      doReplication(dbUser); 
     } 
    } 
} 
+0

嘗試提供關於樂觀鎖定異常的詳細信息,該塊synchnized不是解決此問題的方法。 –

+0

@Vash如果是解決方案,我不會發布這個問題!換句話說,我的問題可能是:避免多個線程在db中編寫相同記錄的解決方案是什麼。因爲如果他們這樣做,可能會導致一個樂觀的鎖定例外......我更新了'synchronized'塊上方的推薦,以使其更清晰 – fischermatte

+0

您是否已經找到了解決這一問題的方法。我也有同樣的情況。我希望我的一個服務方法應該只在已經有一個線程執行相同的用戶ID時才被鎖定。如果不同的用戶ID出現,那麼它不應該被鎖定。 – roanjain

回答

1

你最好把鎖,因爲這是保證,一旦兩個字符串是由相同的內容,intern()將返回相同的對象他們。

此外,如果在您的系統中有保證,只有一個AuthenticatedUser類的實例具有特定的用戶名,那麼您可以直接在authenticatedUser上鎖定。

1

正如你所提到的,對authenticatedUser.getUserName()進行同步將不起作用,因爲你可能有多個authenticatedUser實例。如果從不同的EntityManager上下文中讀取,則在相同的authenticatedUser數據中讀取的兩個線程將獲得不同的實例。爲了解決這個問題,可以通過用try/catch塊封裝doReplication方法來解決偶然的樂觀鎖異常,然後檢查更改是否由另一個線程完成(使用em.refresh),或者可以切換到使用這裏描述悲觀鎖: http://wiki.eclipse.org/EclipseLink/Examples/JPA/Locking#Pessemistic_Locking http://wiki.eclipse.org/EclipseLink/Examples/JPA/PessimisticLocking

一旦你鎖定authenticatedUser,您可以檢查它是否被複制和釋放鎖或進行復制。