2016-01-06 75 views
0

您好我正陷入一個JavaFX應用程序的死鎖,我不知道爲什麼會發生這種情況...... 初始化我的應用程序時,我啓動一個Thread來加載創建一個擴展我的DatabaseManager的對象的特定視圖。同時,另一個線程在另一個視圖上執行相同的操作,另一個對象正在擴展DatabaseManager。爲什麼這個僵局?

進入下列構造函數的第一個線程進入同步塊,但從未到達「System.out.println(」**** 3「);」線。 發生這種情況後,我稍後開始線程進入構造函數,當然因爲資源從未再次被釋放而被阻塞。 由線程1. 任何想法,爲什麼這導致了死鎖?我使用javafx.concurrent.Task與java.lang.Thread中

public abstract class DatabaseManager { 

protected static final AtomicReference<EntityManager> entityManager = new AtomicReference<>(); 

protected DatabaseManager() { 
    if (entityManager.get() == null) { 
       System.out.println("****1"); 
     synchronized (entityManager) { 
      if (entityManager.get() == null) { 
       System.out.println("****2"); 
       entityManager.set(Persistence.createEntityManagerFactory(
         DatabaseConstants.hsqlPersistenceUnitName, 
         DatabaseConstants.getProperties()).createEntityManager()); 
       System.out.println("****3"); 
      } 
     } 
    } 
} 
... 

回答

2

AtomicReference S(和他們的基本類型的包裝朋友)管理自己的原子。所以,雖然我不明白爲什麼這是僵局,但使用同步塊使用AtomicReference首先會破壞AtomicReference的整個目的。

你可以這樣做:

protected DatabaseManager() { 
    entityManager.compareAndSet(null, 
     Persistence.createEntityManagerFactory(
      DatabaseConstants.hsqlPersistenceUnitName, 
      DatabaseConstants.getProperties()).createEntityManager()); 
} 

這將有完全按照你正在嘗試做的(沒有日誌記錄,顯然)相同的效果。

的推薦方式懶洋洋地初始化靜態字段是使用「延遲初始化holder類成語」:

public abstract class DatabaseManager { 

    protected static EntityManager getEntityManager() { 
     return EntityManagerHolder.entityManager ; 
    } 

    private static class EntityManagerHolder { 
     static final EntityManager entityManager = 
      Persistence.createEntityManagerFactory(
       DatabaseConstants.hsqlPersistenceUnitName, 
       DatabaseConstants.getProperties()).createEntityManager() ; 
     } 
    } 
} 

這確保延遲初始化,因爲內部類DatabaseManager.EntityManagerHolder沒有加載,直到它被用於引用第一次,直到getEntityManager()第一次被調用才發生。它保證是原子的,因爲類初始化器是保證原子的。此外,由於僅當內部類被初始化時才實施原子性,所以在隨後調用getEntityManager()時不會發生同步的成本。 (相比之下,與AtomicReference解決方案執行到AtomicReference.compareAndSet(...)每次創建新DatabaseManager時間(大概是內部同步)調用。)

見喬希布洛赫的有效的Java,項目71,對於更詳細的討論。

0

我發現了我的死鎖事件的解決方案,儘管我不知道爲什麼會導致死鎖...... 我只是嘗試訪問另一個數據庫的另一個線程。該應用程序與2個數據庫進行交互。在我的HSQL數據庫中的所有performings從我的DatabaseManager來了,當一個線程試圖初始化的EntityManager在我的DatabaseManager第三主題是簡單地調用

Persistence.createEntityManagerFactory(DBConstants.ORACLE_PERSISTENCE_UNIT).createEntityManager(); 

刪除該行後,也使用DatabaseManager,以建立連接第二個數據庫的死鎖消失了。 但我不知道爲什麼。我眼中唯一可能的解決方案是eclipselink本身在那裏死鎖...