2013-02-04 2 views
1

Я не очень разбираюсь в многопоточности на Java. Я хочу установить блокировку для блока кода. В моем случае я хочу избежать оптимистических исключений блокировки, выполняя некоторую синхронизацию для определенного пользователя. Метод replicateUser может быть вызван несколькими потоками для одного и того же пользователя. Но не гарантируется, что authenticatedUser - это всегда один и тот же объект.Как эффективно блокировать кодовый блок, чтобы избежать оптимистического исключения блокировки

Итак, как я могу эффективно заблокировать этот раздел? Я не хочу, чтобы раздел был заблокирован для всех потоков, но только для тех, у кого один и тот же пользователь. Могу ли я поместить блокировку на строковые объекты, как показано в примере ниже, используя getUserName()?

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

Постарайтесь предоставить подробную информацию об исключении Optimistic Lock Exception, блок synchnized не является решением этой проблемы. –

+0

@Vash, если бы это было решение, я бы не разместил этот вопрос! мой вопрос, другими словами, мог бы быть следующим: каково решение, чтобы избежать нескольких потоков, записывающих одну и ту же запись в db. потому что, если они это сделают, это может привести к оптимистическому исключению блокировки ... Я обновил замечание над блоком «synchronized», чтобы сделать его более понятным. – fischermatte

+0

Вы выяснили путь для этого. У меня тоже такое же состояние. я хочу, чтобы один из моих методов в сервисе был заблокирован только тогда, когда уже выполняется поток для одного и того же идентификатора пользователя. Если появляется другой идентификатор пользователя, он не должен быть заблокирован. – roanjain

ответ

1

Вам лучше замок надеть authenticatedUser.getUserName().intern(), потому что это гарантирует, что когда две строки идентичны по содержанию, intern() будет возвращать один и тот же объект для них.

Кроме того, если в вашей системе гарантировано, что существует только один экземпляр класса AuthenticatedUser с конкретным именем пользователя, вы можете заблокировать его непосредственно на authenticatedUser.

1

Как вы упомянули, синхронизация на authenticatedUser.getUserName() не будет работать, потому что у вас может быть несколько экземпляров authenticatedUser. Два потока, считывающие одни и те же данные аутентифицированного пользователя, получат разные экземпляры, если они считываются из разных контекстов EntityManager. Чтобы обойти это, вы можете либо учитывать случайное оптимистическое исключение блокировки, обернув метод doReplication блоком try/catch, который затем проверяет, что изменение было выполнено другим потоком (с использованием em.refresh), или вы можете переключиться на использование пессимистическим замок, как описано здесь: http://wiki.eclipse.org/EclipseLink/Examples/JPA/Locking#Pessemistic_Locking http://wiki.eclipse.org/EclipseLink/Examples/JPA/PessimisticLocking

После того, как вы заперли authenticatedUser, вы можете проверить, если он был воспроизведен и снять блокировку или выполнить репликацию.

Смежные вопросы