Java 当不同线程使用web方法时,使其同步是一种好的做法吗?
我在代码审查论坛上问了一个类似的问题,但有人建议我在这里问这个问题。 我想知道下面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对象的主键值。这就是同步
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();
}
}