如何创建正确的惰性单例?

发布于 2025-01-13 01:07:20 字数 2882 浏览 0 评论 0原文

我有这个类

public class Singletons {
    private static UserService userService;
    private static OrderService orderService;

    public static UserService getUserService() {
        if (userService == null) {
            synchronized (Singletons.class) {
                if (userService == null)
                    userService = new UserService();
            }
        }

        return userService;
    }

    public static OrderService getOrderService() {
        if (orderService == null) {
            synchronized (Singletons.class) {
                if (orderService == null)
                    orderService = new OrderService();
            }
        }

        return orderService;
    }
}

Intellij IDEA 向我展示了这个警告:

双重检查锁定尝试按需初始化字段并在 线程安全的方式同时避免了同步的成本。 不幸的是,当用于非线程安全的字段时,它不是线程安全的。 声明为挥发性的。使用 Java 1.4 或更早版本时,请仔细检查 即使对于易失性字段,锁定也不起作用。阅读文章 上面链接了问题的详细解释。

此链接:“双重检查锁定已损坏”声明< /a>

我读了这篇文章,但我不明白如何修复我的课程。据我了解,我可以执行以下操作:

public class Singletons {
    private static volatile UserService userService;
    private static volatile OrderService orderService;

    public static UserService getUserService() {
        if (userService == null) {
            synchronized (Singletons.class) {
                if (userService == null)
                    userService = new UserService();
            }
        }

        return userService;
    }

    public static OrderService getOrderService() {
        if (orderService == null) {
            synchronized (Singletons.class) {
                if (orderService == null)
                    orderService = new OrderService();
            }
        }

        return orderService;
    }
}

这足够了吗?(EDDIT - 我使用 java > 1.4,所以它不适合我)或者第二种方法可能是这样的:

public class Singletons {
    private static final UserService userService = new UserService();
    private static final OrderService orderService = new OrderService();

    public static UserService getUserService() {
        return userService;
    }

    public static OrderService getOrderService() {
        return orderService;
    }
}

但它看起来很奇怪。如果我需要将其他类传递给构造函数怎么办?看起来不对。 也许是这样,就像这个答案(StackOverflow答案):

public class Singletons {
    private static class Ref {
        static final UserService userService = new UserService();
        static final OrderService orderService = new OrderService();
    }

    public static UserService getUserService() {
        return Ref.userService;
    }

    public static OrderService getOrderService() {
        return Ref.orderService;
    }
} 

但它看起来与前一个相同。那么如何创建正确的惰性单例呢?

I have this class

public class Singletons {
    private static UserService userService;
    private static OrderService orderService;

    public static UserService getUserService() {
        if (userService == null) {
            synchronized (Singletons.class) {
                if (userService == null)
                    userService = new UserService();
            }
        }

        return userService;
    }

    public static OrderService getOrderService() {
        if (orderService == null) {
            synchronized (Singletons.class) {
                if (orderService == null)
                    orderService = new OrderService();
            }
        }

        return orderService;
    }
}

Intellij IDEA shows me this warrnig:

Double-checked locking tries to initialize a field on demand and in a
thread-safe manner while avoiding the cost of synchronization.
Unfortunately it is not thread-safe when used on a field that is not
declared volatile. When using Java 1.4 or earlier, double-checked
locking doesn't work even with volatile fields. Read the article
linked above for the detailed explanation of the problem.

And this link: The "Double-Checked Locking is Broken" Declaration

I read this article but I can not understand how I can fix my class. As I understood I can do the following:

public class Singletons {
    private static volatile UserService userService;
    private static volatile OrderService orderService;

    public static UserService getUserService() {
        if (userService == null) {
            synchronized (Singletons.class) {
                if (userService == null)
                    userService = new UserService();
            }
        }

        return userService;
    }

    public static OrderService getOrderService() {
        if (orderService == null) {
            synchronized (Singletons.class) {
                if (orderService == null)
                    orderService = new OrderService();
            }
        }

        return orderService;
    }
}

Is this enough?(EDDIT - I use java > 1.4 so it is not for me) Or the second approach might be like this:

public class Singletons {
    private static final UserService userService = new UserService();
    private static final OrderService orderService = new OrderService();

    public static UserService getUserService() {
        return userService;
    }

    public static OrderService getOrderService() {
        return orderService;
    }
}

But it looks strange. What if I need to pass other classes to the constructor? It looks wrong.
Maybe this, like in this answer(StackOverflow answer):

public class Singletons {
    private static class Ref {
        static final UserService userService = new UserService();
        static final OrderService orderService = new OrderService();
    }

    public static UserService getUserService() {
        return Ref.userService;
    }

    public static OrderService getOrderService() {
        return Ref.orderService;
    }
} 

But it looks the same as the previous one. So How can I create the correct lazy singleton?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

故事和酒 2025-01-20 01:07:20

有多种方法可以解决这个问题。最简单的方法是根本不使用双重检查锁定,而是同步整个方法。对于早期版本的 JVM,出于性能原因,通常不建议同步整个方法。但在较新的 JVM 中,同步性能已得到很大提高,因此现在这是首选解决方案。如果您希望完全避免使用同步,则可以使用内部静态类来保存引用。内部静态类保证延迟加载。

解决方案1.同步方法

public class Singletons {
    private static UserService userService;

    public static synchronized UserService getUserService() {
        if (userService == null) {
            userService = new UserService();
        }
        return userService;
    }
}

解决方案2.嵌套静态类
您描述的解决方案,但将实例拆分为几个静态内部类。它将保证每个实例都是按需创建的。在您的示例中,当您调用其中之一时,将创建两个实例。
类初始化发生在我们第一次使用其方法或字段之一时。 Java 虚拟机负责同步和递归初始化。请参阅文档

public class Singletons {
    private static class UserServiceRef {
        static final UserService userService = new UserService();
    }

    private static class OrderServiceRef {
        static final OrderService orderService = new OrderService();
    }

    public static UserService getUserService() {
        return UserServiceRef.userService;
    }

    public static OrderService getOrderService() {
        return OrderServiceRef.orderService;
    }
} 

对于我来说,解决方案 2 更可取,因为它没有使用 synchronized。 JWM 负责同步并保证类延迟加载。

There are multiple ways to fix this. The simplest one is to simply not use double-checked locking at all and synchronize the whole method instead. With early versions of the JVM, synchronizing the whole method was generally advised against for performance reasons. But synchronized performance has improved a lot in newer JVMs, so this is now a preferred solution. If you prefer to avoid using synchronized altogether, you can use an inner static class to hold the reference instead. Inner static classes are guaranteed to load lazily.

Solution 1. Synchronized method

public class Singletons {
    private static UserService userService;

    public static synchronized UserService getUserService() {
        if (userService == null) {
            userService = new UserService();
        }
        return userService;
    }
}

Solution 2. Nested static class
The solution which you described, but split instances into several static inner classes. It will guarantee that each instance will be created on-demand. In your example, two instances will be created when you call one of them.
Class initialization occurs the first time we use one of its methods or fields. Java Virtual Machine is responsible for taking care of synchronization and recursive initialization. See documentation.

public class Singletons {
    private static class UserServiceRef {
        static final UserService userService = new UserService();
    }

    private static class OrderServiceRef {
        static final OrderService orderService = new OrderService();
    }

    public static UserService getUserService() {
        return UserServiceRef.userService;
    }

    public static OrderService getOrderService() {
        return OrderServiceRef.orderService;
    }
} 

As for me Solution 2 more preferable because it is not using synchronized. JWM is responsible for the synchronization and classes are guaranteed to load lazily.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文