在不同线程使用时,使Web方法同步是一种好习惯吗?

时间:2012-06-25 07:26:28

标签: java web-services synchronization eclipselink

我在Code Review论坛中提出了类似的问题,但建议在这里提出这个问题。 我想知道下面的网络方法中的synchronized关键字。由于从线程池调用setPerson(意味着不同的线程可以调用它),我应该以某种方式同步它。当我的客户端对方法进行SOAP调用时,EclipseLink使用thead池。我的问题是,制作网络方法synchronized是一种好习惯,还是可以与em.lock(person, WRITE)进行同步?

@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();
    }
}

修改
我在上面的代码中添加了一行,我在其中设置了person对象的主键值。这就是同步的目的,而不是任何共享的Java对象。我需要同步它,因此两个线程无法获得相同的主键。

1 个答案:

答案 0 :(得分:1)

你可能会问错误的问题。同步在这里没有帮助,因为唯一有并发问题的部分是getLastInsertedId():您不希望两种方法获取相同的值并尝试使用该ID持久保存实例。

同步setPerson只会解决问题,如果它是唯一可以保留Person的方法。

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

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