Java singleton工厂中的同步和锁定

Java singleton工厂中的同步和锁定,java,multithreading,locking,singleton,synchronized,Java,Multithreading,Locking,Singleton,Synchronized,我有一个单例工厂(编辑:重命名为“loader”以避免与工厂模式混淆),它创建对象(在我的示例DAO中)或在已经创建的情况下返回对象: public class DAOLoader { private static final DAOLoader INSTANCE = new DAOLoader(); private UserDAO userDAO; private MessageDAO messageDAO; private final Object lo

我有一个单例工厂(编辑:重命名为“loader”以避免与工厂模式混淆),它创建对象(在我的示例DAO中)或在已经创建的情况下返回对象:

public class DAOLoader {

    private static final DAOLoader INSTANCE = new DAOLoader();

    private UserDAO userDAO;
    private MessageDAO messageDAO;

    private final Object lockUserDAO = new Object();
    private final Object lockMessageDAO = new Object();

    private DAOLoader() {}

    public static DAOLoader getInstance() {
        return INSTANCE;
    }

    public UserDAO getUserDAO() {
        if (userDAO == null) {
            synchronized(lockUserDAO) {
                if (userDAO == null) userDAO = new UserDAO();
            }
        }
        return userDAO;
    }

    public MessageDAO getMessageDAO() {
        if (messageDAO == null) {
            synchronized(lockMessageDAO) {
                if (messageDAO == null) messageDAO = new MessageDAO();
            }
        }
        return messageDAO;
    }
}
首先,你们看到这个代码有什么问题吗?
在本例中,每个方法需要不同的锁,还是应该只使用一个全局锁?使用唯一的全局锁是否会发生死锁?如果不是,唯一的缺点是,如果某个线程使用锁来创建DAO,而另一个线程想要创建另一个DAO,那么它必须等待锁被释放


谢谢。

您的示例似乎有点混乱,因为您正在阻止DaoLoader的构造函数可见,但并没有阻止Dao构造函数可见。还有一个loader类可能会变成一个垃圾场,它鼓励按层而不是按特性进行组织

你可以考虑使用:


holder静态类在调用访问它的方法之前不会初始化,因为它是在第一次访问时初始化的(类初始化是串行的),不需要同步。

唯一的缺点是什么?远不止这些。全局可见的对象(如)不会缩放。谷歌有一个单身猎手来识别和删除他们:我认为那里甚至没有工厂设计。检查这个@duffymo“全局可见对象,比如不会缩放”你是什么意思?@NathanHughes这是一个我不能使用Spring或任何DI框架的项目,我只想创建一次DAO并重用它们。让我为你简化一下:不要创建单例或所有这些锁定代码。将您的连接集中起来,并在尽可能狭窄的范围内使用它们。学习Spring——他们编写了一个比你更好的JDBC框架。@Ravindra:这就是getInstance方法。我冒昧地简化了发布的示例,去掉了DaoLoader。我认为它比双锁单例更好。顺便说一句,用户实例是否需要易失性?@Ravindra:不,它不需要易失性。因为它是最终的,所以在初始化类时它会安全地发布。明白了。我已经迷失在懒惰的单身汉的双重锁定忧郁中:)@NathanHughes正如我在我的问题下的评论中所说的,急切的初始化是故意的。DAO构造函数是可见的,因为它们可能通过加载程序使用,也可能不通过加载程序使用,我还向它们传递参数(如数据源)。无论如何,我的问题更多的是关于唯一/相同锁和同步;-)
public class UserDao {
    private UserDao() {}

    String findById(Long id) {
        return "foo";
    }

    private static class LazyUserDaoHolder {
        static final UserDao USER_DAO_INSTANCE = new UserDao();
    }

    public static UserDao getInstance() {
        return LazyUserDaoHolder.USER_DAO_INSTANCE;
    }
}