Java 当不同线程使用web方法时,使其同步是一种好的做法吗?

Java 当不同线程使用web方法时,使其同步是一种好的做法吗?,java,web-services,synchronization,eclipselink,Java,Web Services,Synchronization,Eclipselink,我在代码审查论坛上问了一个类似的问题,但有人建议我在这里问这个问题。 我想知道下面web方法中的synchronized关键字。由于setPerson是从线程池调用的(这意味着不同的线程可以调用它),因此我应该以某种方式对其进行同步。EclipseLink在客户端对方法进行SOAP调用时使用thead池。我的问题是,使web方法同步是一种好的做法,还是可以使用em.lock(person,WRITE)进行同步 编辑 我在上面的代码中又添加了一行,在那里我设置了person对象的主键值。这就是同步

我在代码审查论坛上问了一个类似的问题,但有人建议我在这里问这个问题。 我想知道下面web方法中的
synchronized
关键字。由于
setPerson
是从线程池调用的(这意味着不同的线程可以调用它),因此我应该以某种方式对其进行同步。EclipseLink在客户端对方法进行SOAP调用时使用thead池。我的问题是,使web方法
同步是一种好的做法,还是可以使用
em.lock(person,WRITE)
进行同步

编辑

我在上面的代码中又添加了一行,在那里我设置了person对象的主键值。这就是同步的目的,而不是任何共享java对象。我需要同步它,以便两个线程无法获得相同的主键。

您可能问错了问题。同步在这里对您没有帮助,因为唯一涉及并发性的部分是
getLastInsertedId()
:您不希望两个方法获得相同的值并尝试持久化具有该ID的实例

同步
setPerson
只能解决问题,前提是它是唯一一种保持
Person
的方法

如果可能,使用底层数据存储的自动递增功能;否则,您的ORM解决方案会执行上下文范围的ID分配吗?最后一种方法是使用
getNextId
方法,该方法可以同步并返回递增的值。这可能会导致数据库中出现不连续的ID序列(
getNextId
不知道持久化操作是否成功),但这会减少锁定的范围


正如JB Nizet所指出的,ID分配需要持久化,并以某种方式提供给此数据存储的所有客户端。如果有两个应用程序实例持久化
Person
实例,则需要确保它们共享一个ID分配器。

代码仅使用局部变量。为什么要同步它。非方面:您不应该在每个方法中创建新的EntityManagerFactory。创建一次,并始终重用唯一的实例。是的,变量是本地的,但我担心的是数据库事务。由于PK:s不是自动递增的,因此两个或多个线程可能会调用` setPerson()',并写入相同的主键。因此,同步不是针对共享java对象,而是针对数据库访问。同步不是正确的解决方案,因为它不会处理由其他方法保存的人员、由其他应用程序保存的人员或由群集中的其他JVM保存的人员的情况。如果该人员由其他应用程序或其他JVM保存,则您是对的,但是如果所有处理Person对象的方法都是同步的,那么什么方法可以持久化Person就不重要了。对吗?我将按照您的建议删除同步并处理catch块中可能发生的异常。:-)不需要。所有方法都需要在同一个对象上同步。
@Override
public synchronized void setPerson(Person person) {
    EntityManagerFactory emf = Persistence.createEntityManagerFactory("PersonLibPU");            
    EntityManager em = emf.createEntityManager(); 
    if(!em.getTransaction().isActive()) {
       em.getTransaction().begin();
    }
    try {
         person.setPersonId(getLastInsertedId() + 1); // Get the last inserted ID and increment it by 1
         em.merge(person);
         em.getTransaction().commit();  
         emf.getCache().evict(Person.class);                    
    } catch (Exception ex) {
         if(em.getTransaction().isActive())
            em.getTransaction().rollback();
    } finally {
        em.close();
    }
}