单列模式有很多种写法,以前我知道懒汉式和饿汉式,其实还有很多的方法,并且可能还比懒汉式和饿汉式更优良。
个人觉得最简单,类在加载时就 new出来了。
public class HungrySingleton {
private static final HungrySingleton instance = new HungrySingleton();
private HungrySingleton(){}
public static HungrySingleton getInstance(){
return instance;
}
}
❝优点:线程安全、逻辑简单 缺点:如果这种写法被大量使用的话,导致内存开销增加
调用方法的时候才new,这种方式需要考虑线程安全问题。面试最喜欢问这个。
public class LazySimpleSingleton {
private static volatile LazySimpleSingleton instance = null; //(1)
private LazySimpleSingleton(){
if (instance != null) {
throw new RuntimeException("该构造方法禁止获取");
}
} //(2)
public static LazySimpleSingleton getInstance() {
if (instance == null) {
synchronized (LazySimpleSingleton.class) {
if (instance == null) {
instance = new LazySimpleSingleton();
}
}
} //(3)
return instance;
}
}
如上所示代码,(1)加了volatile,为了防止指令重排,如果不加,很可能第一个线程没有完全将其实例化完,第二个线程获取到的示例就会有问题。(2)在构造函数中加了判断,是为了防止被反射创建实例。(3)加了synchronized,为了全程安全,保证只创建一个实例。
public class LazyInnerClassSingleton {
private LazyInnerClassSingleton() {
if (LazyHolder.INSTANCE != null) {
throw new RuntimeException("该构造方法禁止获取");
}
}
public static final LazyInnerClassSingleton getInstance() {
return LazyHolder.INSTANCE;
}
private static class LazyHolder {
private static final LazyInnerClassSingleton INSTANCE = new LazyInnerClassSingleton();
}
}
内部类会在调用的时候才加载,并只加载一次。利用这个特性可以实现 单列模式。
public class ThreadLocalSingleton {
private static final ThreadLocal<ThreadLocalSingleton> threadLocalInstance = ThreadLocal.withInitial(() -> new ThreadLocalSingleton());
private ThreadLocalSingleton(){}
public static ThreadLocalSingleton getInstance(){
return threadLocalInstance.get();
}
public static void main(String[] args){
ThreadLocalSingleton instance1 = ThreadLocalSingleton.getInstance();
ThreadLocalSingleton instance2 = ThreadLocalSingleton.getInstance();
System.out.println(instance1 == instance2);
}
}
如上代码,利用ThreadLocal线程隔离的特性实现。
public class ContainerSingleton {
private ContainerSingleton(){}
private static Map<String,Object> ioc = new ConcurrentHashMap<>();
public static Object getInstance(String className) {
synchronized (ioc) {
if (!ioc.containsKey(className)) {
Object obj = null;
try {
Class.forName(className).newInstance();
ioc.put(className,obj);
} catch (Exception e) {
e.printStackTrace();
}
return obj;
} else {
return ioc.get(className);
}
}
}
}
仿照Spring的Ioc容器实现。
public enum EnumSingleton {
INSTANCE;
private Object data;
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public EnumSingleton getInstance() {
return INSTANCE;
}
}
《Effective Java》作者力荐,线程安全,不用怕被暴力反射破解。
public class Singleton {
private Singleton() {
}
private static AtomicReference<Singleton> singletonAtomicReference = new AtomicReference<>();
public static Singleton getInstance() {
while (true) {
Singleton singleton = singletonAtomicReference.get();// 获得singleton
if (singleton != null) {// 如果singleton不为空,就返回singleton
return singleton;
}
// 如果singleton为空,创建一个singleton
singleton = new Singleton();
// CAS操作,预期值是NULL,新值是singleton
// 如果成功,返回singleton
// 如果失败,进入第二次循环,singletonAtomicReference.get()就不会为空了
if (singletonAtomicReference.compareAndSet(null, singleton)) {
return singleton;
}
}
}
}
好了,单列模式就分享都这里了。