在单利类首次加载时就创建实例
缺点:浪费内存空间
public class HungrySingleton {
private static final HungrySingleton hungrySingleton = new HungrySingleton();
public HungrySingleton() {
}
public static HungrySingleton getInstance() {
return hungrySingleton;
}
}
public class HungryStaticSingleton {
private static final HungryStaticSingleton hungrySingleton;
static {
hungrySingleton = new HungryStaticSingleton();
}
public HungryStaticSingleton() {
}
public static HungryStaticSingleton getInstance() {
return hungrySingleton;
}
}
不加synchronized会出现线程不安全的问题,以下方法还是可能会出现问题。
1.普通
public class LazySimpleSingleton {
private static LazySimpleSingleton lazySimpleSingleton = null;
// 虽然内部类私有,但是反射可以拿到
private LazySimpleSingleton() {
}
// JDK1.6 之后对synchronize性能优化不少
// 不可避免的存在一定的性能问题
public synchronized static LazySimpleSingleton getInstance() {
if (lazySimpleSingleton == null) {
lazySimpleSingleton = new LazySimpleSingleton();
}
return lazySimpleSingleton;
}
}
2.改进-双重检测锁
需要牺牲一定的性能
public class LazyDoubleCheckSingleton {
private volatile static LazyDoubleCheckSingleton lazySimpleSingleton = null;
private LazyDoubleCheckSingleton() {
}
// 双重检查锁
public static LazyDoubleCheckSingleton getInstance() {
if (lazySimpleSingleton == null) {
synchronized (LazyDoubleCheckSingleton.class) {
if (lazySimpleSingleton == null) {
lazySimpleSingleton = new LazyDoubleCheckSingleton();
// CPU执行时会转换成JVM指令行
// 指令重排序问题
// 1.分配内存给这个对象
// 2.初始化对象
// 3.讲初始化好的对象和内存地址建立关联,赋值
// 4.用户初次访问
}
}
}
return lazySimpleSingleton;
}
}
3.内部类模式
以下方法性能很高,但是会被反射破坏单例
// 全程没有用synchronized关键字
public class LazyInnerClassSingleton {
// 虽然内部类私有,但是反射可以拿到
private LazyInnerClassSingleton() {}
// 懒汉式单例
// LazyHolder 里面的逻辑需要等到外部方法调用时才执行
// 巧妙的利用了内部类的特性
// JVM 底层执行逻辑,完美避免了线程安全问题
public static final LazyInnerClassSingleton getInstance() {
return LazyHolder.LAZY;
}
private static class LazyHolder {
private static final LazyInnerClassSingleton LAZY = new LazyInnerClassSingleton();
}
}
使用反射破坏单例模式
try {
Class<?> clazz = LazyInnerClassSingleton.class;
Constructor c = clazz.getDeclaredConstructor(null);
c.setAccessible(true);
Object o1 = c.newInstance();
Object o2 = LazyInnerClassSingleton.getInstance();
System.out.println(o1);
System.out.println(o2);
System.out.println(o1 == o2);
c.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
3.改进内部类单例
// 全程没有用synchronized关键字
public class LazyInnerClassSingleton {
// 虽然内部类私有,但是反射可以拿到
private LazyInnerClassSingleton() {
if (LazyHolder.LAZY != null) {
throw new RuntimeException("不允许构建多个示例");
}
}
// 懒汉式单例
// LazyHolder 里面的逻辑需要等到外部方法调用时才执行
// 巧妙的利用了内部类的特性
// JVM 底层执行逻辑,完美避免了线程安全问题
public static final LazyInnerClassSingleton getInstance() {
return LazyHolder.LAZY;
}
private static class LazyHolder {
private static final LazyInnerClassSingleton LAZY = new LazyInnerClassSingleton();
}
}
//反序列化时导致单例破坏
public class SeriableSingleton implements Serializable {
//序列化就是说把内存中的状态通过转换成字节码的形式
//从而转换一个IO流,写入到其他地方(可以是磁盘、网络IO)
//内存中状态给永久保存下来了
//反序列化
//讲已经持久化的字节码内容,转换为IO流
//通过IO流的读取,进而将读取的内容转换为Java对象
//在转换过程中会重新创建对象new
public final static SeriableSingleton INSTANCE = new SeriableSingleton();
private static final long serialVersionUID = 1463169805620377688L;
private SeriableSingleton(){}
public static SeriableSingleton getInstance(){
return INSTANCE;
}
private Object readResolve(){
return INSTANCE;
}
}
public enum EnumSingleton {
INSTANCE;
private Object data;
public static EnumSingleton getInstance() {
return INSTANCE;
}
public Object getData() {
return data;
}
}
public class ContainerSingleton {
private ContainerSingleton() {
}
private static Map<String, Object> ioc = new ConcurrentHashMap<>();
public static Object getBean(String className) {
synchronized (ioc) {
if (!ioc.containsKey(className)) {
Object obj = null;
try {
obj = Class.forName(className).newInstance();
ioc.put(className, obj);
} catch (Exception e) {
e.printStackTrace();
}
return obj;
}
return ioc.get(className);
}
}
}