Jpa 为什么会出现僵局?

Jpa 为什么会出现僵局?,jpa,javafx,deadlock,Jpa,Javafx,Deadlock,您好,我在JavaFX应用程序中遇到了死锁,我不知道为什么会发生这种情况。。。 初始化应用程序时,我启动一个线程来加载某个视图,该视图正在创建一个扩展DatabaseManager的对象。同时,另一个线程正在扩展DatabaseManager的另一个视图和另一个对象上执行相同的操作 进入以下构造函数的第一个线程进入同步块,但从未到达“System.out.println(“*****3”);”行。 发生这种情况后,我后来启动的线程进入构造函数,当然被阻塞了,因为资源再也没有被释放过。 通过线程1

您好,我在JavaFX应用程序中遇到了死锁,我不知道为什么会发生这种情况。。。 初始化应用程序时,我启动一个线程来加载某个视图,该视图正在创建一个扩展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");
            }
        }
    }
}
...
公共抽象类数据库管理器{
受保护的静态最终AtomicReference entityManager=新的AtomicReference();
受保护的数据库管理器(){
if(entityManager.get()==null){
系统输出打印项次(“**1”);
已同步(entityManager){
if(entityManager.get()==null){
系统输出打印项次(“**2”);
set(Persistence.createEntityManagerFactory(
DatabaseConstants.hsqlPersistenceUnitName,
DatabaseConstants.getProperties()).createEntityManager();
系统输出打印项次(“**3”);
}
}
}
}
...

AtomicReference
s(以及他们的原始包装器朋友)管理自己的原子性。因此,虽然我真的不明白这是死锁的原因,但使用同步块来使用
AtomicReference
首先破坏了
AtomicReference
的全部目的

您只需执行以下操作:

protected DatabaseManager() {
    entityManager.compareAndSet(null, 
         Persistence.createEntityManagerFactory(
             DatabaseConstants.hsqlPersistenceUnitName,
             DatabaseConstants.getProperties()).createEntityManager());
}
这将产生与您尝试执行的操作完全相同的效果(显然,没有日志记录)

惰性初始化静态字段的推荐方法是使用“惰性初始化持有者类习惯用法”:

这确保了延迟初始化,因为内部类
DatabaseManager.EntityManager文件夹在第一次引用之前不会加载,而在
getEntityManager()之前不会加载
是第一次调用。它是保证原子的,因为类初始值设定项是保证原子的。此外,由于原子性仅在内部类初始化时强制执行,因此后续调用
getEntityManager()
时不会产生同步成本。(相比之下,使用
AtomicReference
的解决方案在每次创建新的
数据库管理器时执行对
AtomicReference.compareAndSet(…)
的调用(可能是内部同步的)


请参阅Josh Bloch的有效Java,第71项,以获得更全面的讨论。

我找到了死锁事件的解决方案,尽管我不知道为什么会导致死锁。。。 我只有另一个线程正在尝试访问另一个数据库。该应用程序与两个数据库交互。我的HSQL数据库上的所有性能都来自我的DatabaseManager,当一个线程试图初始化DatabaseManager中的EntityManager时,第三个线程只是在调用

Persistence.createEntityManagerFactory(DBConstants.ORACLE_PERSISTENCE_UNIT).createEntityManager();
删除该行并使用DatabaseManager建立到第二个数据库的连接后,死锁消失了。 但我不知道为什么。在我看来,唯一可能的解决办法是日食本身在那里陷入僵局

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