我已经读过可以Singleton使用以下方法在Java中实现Enum:
public enum MySingleton {
INSTANCE;
}
Run Code Online (Sandbox Code Playgroud)
但是,上面的工作如何?具体而言,Object必须实例化.在这里,如何MySingleton被实例化?谁在做什么new MySingleton()?
要执行无锁和无等待的延迟初始化,请执行以下操作:
private AtomicReference<Foo> instance = new AtomicReference<>(null);
public Foo getInstance() {
Foo foo = instance.get();
if (foo == null) {
foo = new Foo(); // create and initialize actual instance
if (instance.compareAndSet(null, foo)) // CAS succeeded
return foo;
else // CAS failed: other thread set an object
return instance.get();
} else {
return foo;
}
}
Run Code Online (Sandbox Code Playgroud)
除了一件事之外,它的效果非常好:如果两个线程看到实例null,它们都会创建一个新对象,只有一个幸运的是通过CAS操作设置它,这会浪费资源.
有没有人建议另一种无锁延迟初始化模式,这会降低两个并发线程创建两个昂贵对象的可能性?
这是我一直用于工厂的基本模式的示例,它返回一个线程安全的Singleton:
public class UserServiceFactory {
private volatile static UserService userService;
private UserServiceFactory() { }
public static UserService getInstance() {
if (userService == null) {
synchronized(UserServiceImpl.class) {
if (userService == null) {
userService = new UserServiceImpl();
}
}
}
return userService;
}
}
Run Code Online (Sandbox Code Playgroud)
它使用volatile和double check惯用法来确保创建单个实例并在线程中可见.
是否有更简洁和/或更便宜的方式来实现1.6+中的相同目标.
我正在阅读文章Double-checked locking和Singleton模式,关于双重检查锁定如何被破坏,以及Stack Overflow上的一些相关问题.
我已经多次使用这种模式/习语而没有任何问题.由于我一直在使用Java 5,我首先想到的是这已经在Java 5内存模型中得到了纠正.然而文章说:
本文引用了Java 5.0之前的Java内存模型; 关于内存排序的陈述可能不再正确.然而,在新的内存模型下,双重检查的锁定习惯仍然被打破.
这是一个真正的问题,如果是这样,在什么条件下?
我有一个简单的类,它在自己的线程中进行一些计算,并将结果报告给监听器.
class Calculator extends Thread {
protected Listener listener;
public void setListener(Listener l) {
listener = l;
}
public void run() {
while (running) {
... do something ...
Listener l = listener;
if (l != null) {
l.onEvent(...);
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
在任何时候,如果用户在一段时间内不想要任何事件,则可以调用setListener(null).因此,在run()函数中,我创建了一个侦听器的副本,因此我不能遇到NullPointerException,如果在!= null条件检查成功后将侦听器设置为null,则可能会发生这种情况.就我而言,我相信这是同步它的正确选择.
我的问题是:我应该在这里声明监听器成员变量为volatile吗?我已经阅读了很多关于volatile的内容,但是所有的例子似乎都是针对基本数据类型(boolean,int,...),而不是Objects.因此,我不确定对象是否应该/可以被声明为volatile.我相信我必须声明它是volatile,所以线程总是有成员变量的最新版本,但我不确定.
谢谢!
假设我们使用双重检查锁来实现单例模式:
private static Singleton instance;
private static Object lock = new Object();
public static Singleton getInstance() {
if(instance == null) {
synchronized (lock) {
if(instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
Run Code Online (Sandbox Code Playgroud)
我们是否需要将变量“instance”设置为“volatile”?我听到有人说我们需要它来禁用重新排序:
创建对象时,可能会发生重新排序:
address=alloc
instance=someAddress
init(someAddress)
Run Code Online (Sandbox Code Playgroud)
他们说如果最后两个步骤被重新排序,我们需要一个 volatile 实例来禁用重新排序,否则其他线程可能会得到一个没有完全初始化的对象。
然而,既然我们在一个同步代码块中,我们真的需要 volatile 吗?或者一般来说,我可以说同步块可以保证共享变量对其他线程是透明的,即使它不是 volatile 变量也不会重新排序吗?
根据App Engine文档,PersistenceManagerFactory应该只在应用程序中创建一次.
它提供了这个样本:
package guestbook;
import javax.jdo.JDOHelper;
import javax.jdo.PersistenceManagerFactory;
public final class PMF {
private static final PersistenceManagerFactory pmfInstance =
JDOHelper.getPersistenceManagerFactory("transactions-optional");
private PMF() {}
public static PersistenceManagerFactory get() {
return pmfInstance;
}
}
Run Code Online (Sandbox Code Playgroud)
除了制作一个" "对象之外,为什么还PMF.java必须是" "?public final classpmfInstanceprivate static final