如何有效地锁定代码块以避免乐观锁定异常

时间:2013-02-04 17:15:56

标签: java multithreading jpa optimistic-locking

我对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);
        }
    }
}

2 个答案:

答案 0 :(得分:1)

你最好锁定authenticatedUser.getUserName ().intern ()因为保证一旦两个字符串按内容相同,intern ()将为它们返回相同的对象。

此外,如果系统中有保证,只有一个具有特定用户名的AuthenticatedUser类实例,则可以直接锁定authenticatedUser

答案 1 :(得分: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,就可以检查它是否已被复制并释放锁定或执行复制。