我需要在ObjectDB中拥有一个原子计数器,但是以下代码无法按预期工作:
final EntityManagerFactory emf = Persistence.createEntityManagerFactory("test.odb");
EntityManager em = emf.createEntityManager();
Point p = new Point(0, 0);
em.getTransaction().begin();
em.persist(p);
em.getTransaction().commit();
em.close();
final CountDownLatch l = new CountDownLatch(100);
for (int i = 0; i < 100; i++) {
Thread t = new Thread(new Runnable() {
@Override
public void run() {
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
//Query q = em.createQuery("UPDATE Point SET x = x + 1");
Query query = em.createQuery("UPDATE Point SET x = x + 1");
query.executeUpdate();
em.getTransaction().commit();
em.close();
l.countDown();
}
});
t.start();
}
l.await();
em = emf.createEntityManager();
TypedQuery<Point> myquery = em.createQuery("SELECT p from Point p", Point.class);
List<Point> results = myquery.getResultList();
System.out.println("X coordiate is: " + results.get(0).getX());
em.close();
它应该已经打印出X坐标为100。但是实际上,不是。
我的代码有什么问题?
最佳答案
您可以通过以下方式之一来修复代码:
同步您的更新查询,以便它们将顺序执行,而不是同时执行:
synchronized (lock) {
em.createQuery("UPDATE Point SET x = x + 1").executeUpdate();
}
您的锁对象必须是所有线程共享的一个对象。
或者,通过设置悲观的锁定超时来使用ObjectDB / JPA锁定,例如通过:
Map<String, Integer> properties =
Collections.singletonMap("javax.persistence.lock.timeout", 1000);
EntityManagerFactory emf =
Persistence.createEntityManagerFactory(
"objectdb:$objectdb/db/test.tmp;drop", properties);
然后用带有锁和更新的检索替换UPDATE查询:
Point point = em.find(Point.class, 1, LockModeType.PESSIMISTIC_WRITE);
point.setX(point.getX() + 1);
关于java - 嵌入式ObjectDB的多线程,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/23213969/