您好我在JavaFX应用程序中遇到了死锁,我不确定为什么会发生这种情况...... 初始化我的应用程序时,我启动一个Thread来加载某个视图,该视图正在创建一个扩展我的DatabaseManager的对象。同时另一个Thread在另一个视图和另一个扩展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");
}
}
}
}
...
答案 0 :(得分:2)
AtomicReference
(及其原始包装朋友)管理自己的原子性。因此,虽然我无法真正理解为什么这会导致死锁,但使用同步块来使用AtomicReference
会首先击败AtomicReference
的整个目的。
你可以这样做:
protected DatabaseManager() {
entityManager.compareAndSet(null,
Persistence.createEntityManagerFactory(
DatabaseConstants.hsqlPersistenceUnitName,
DatabaseConstants.getProperties()).createEntityManager());
}
将与您尝试的效果完全相同(显然没有记录)。
懒惰地初始化静态字段的推荐方法是使用&#34; Lazy初始化持有者类习惯用法&#34;:
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
执行(可能是内部同步的)调用。)
请参阅Josh Bloch的 Effective Java ,第71项,以便进行更全面的讨论。
答案 1 :(得分:0)
我找到了解决我死锁问题的方法,但我不知道为什么会导致死锁... 我只有另一个尝试访问另一个数据库的线程。该应用程序与2个数据库进行交互。我的HSQL数据库上的所有执行都来自我的DatabaseManager,当一个线程试图在我的DatabaseManager中初始化EntityManager时,第三个线程只是调用
Persistence.createEntityManagerFactory(DBConstants.ORACLE_PERSISTENCE_UNIT).createEntityManager();
删除该行并使用DatabaseManager建立与第二个数据库的连接后,死锁消失了。 但我不明白为什么。我眼中唯一可能的解决方案是eclipselink本身陷入僵局......