2014-04-22 42 views
1

我需要有一個ObjectDB原子計數器,但如我所料下面的代碼不起作用:多線程與嵌入式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,但在現實中,它沒有。

我的代碼有什麼問題?

回答

0

您可以通過以下方式之一修復您的代碼:

同步您的更新查詢,所以他們將sequently執行,而不是同時:

synchronized (lock) { 
    em.createQuery("UPDATE Point SET x = x + 1").executeUpdate(); 
} 

你鎖定的對象必須是一個對象這是所有線程共享的。或者,通過設置悲觀鎖定超時,例如使用ObjectDB/JPA鎖定,例如使用ObjectDB/JPA鎖定。由:

Map<String, Integer> properties = 
    Collections.singletonMap("javax.persistence.lock.timeout", 1000); 
EntityManagerFactory emf = 
    Persistence.createEntityManagerFactory(
     "objectdb:$objectdb/db/test.tmp;drop", properties); 

,然後用鎖和更新檢索替換更新查詢:

Point point = em.find(Point.class, 1, LockModeType.PESSIMISTIC_WRITE); 
point.setX(point.getX() + 1); 
0

更好地創造了一個點DAO類,並與包裹persist()merge() ...功能​​函數。

另外一個AtomicIntegergetAndIncrement()應該解決您的問題,而不需要同步和鎖定。