懒汉模式:在需要使用对象时,new 一个出来,延迟加载,需要时才生成
缺点:存在多线程问题,可能会实例化多个对象。线程1在new对象之前,线程2已经开始进行null判断导致。加入volatile(禁止指令重排序)和synchronized(同步)修饰虽然可以在一定程度上解决多线程安全问题,但是效率低下。
// 懒汉模式
public class Singleton {
private static Singleton instance = null;
private Singleton() {
// 私有化构造函数,防止外部实例化该类
}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
// 修改后
public class Singleton {
// volatile 避免内存可见性引出的问题
private volatile static Singleton instance = null;
private Singleton() {
// 私有化构造函数,防止外部实例化该类
}
public static Singleton getInstance() {
// 双重检验锁
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
饿汉模式:在一开始就new出对象实例,线程安全
缺点:不能延时加载,可能浪费资源。
// 饿汉模式
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton() {
// 私有化构造函数,防止外部实例化该类
}
public static Singleton getInstance() {
return instance;
}
}
使用内部类实现线程安全和延迟加载:
// 内部类
public class Singleton {
private static class InstanceHolder{
public static final Singleton instance = new Singleton();
}
private Singleton(){
// 私有化构造函数,防止外部实例化该类
}
public static Singleton getInstance(){
return InstanceHolder.instance;
}
}
通过枚举实现单例:
1、线程安全(饿汉模式)
2、不会因为序列化而产生新的实例(因为它自己实现了readResolve方法)
3、防止反射攻击(enum类有abstract修饰,不可实例化)
// 枚举示例1
enum SingletonDemo{
INSTANCE;
public void otherMethods(){
System.out.println("Something");
}
}
// 枚举示例2
public class MyObject {
private enum MyEnumSingleton {
INSTANCE;
private Resource resource;
private MyEnumSingleton() {
resource = new Resource();
}
public Resource getResource() {
return resource;
}
}
public static Resource getResource() {
return MyEnumSingleton.INSTANCE.getResource();
}
}