单例模式(构造器私有)
单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一,有以下特点:
单例类只能有一个实例。
单例类必须自己创建自己的唯一实例。
单例类必须给所有其他对象提供这一实例。
反射可以破坏单例模式!!!
饿汉式
这种方式比较常用,但容易产生垃圾对象 优点:没有加锁,执行效率会提高。 缺点:类加载时就初始化,浪费内存。
package com.lyc.single;
//饿汉式单例
public class Hungry {
//可能会浪费空间
private byte[] bytes1= new byte[1024*1024];
private byte[] bytes2= new byte[1024*1024];
private byte[] bytes3= new byte[1024*1024];
private byte[] bytes4= new byte[1024*1024];
private Hungry(){
}
private static final Hungry instance = new Hungry();//创建对象
public static Hungry getInstance(){
return instance;
}
}
懒汉式
DCL懒汉式:在懒汉式基础上加入双重检验锁,保证线程安全和性能。
package com.lyc.single;
//懒汉式单例模式
public class LazyMan {
private LazyMan(){
}
private volatile static LazyMan lazyMan;
public LazyMan getInstance(){
//双重检测锁模式的懒汉式单例,简称:DCL懒汉式
if (lazyMan==null){
synchronized (LazyMan.class){
if (lazyMan==null){
lazyMan=new LazyMan();//不是一个原子性操作
//1.分配内存给这个对象
//2.执行构造方法,初始化对象
//3.将这个对象指向这个空间
//可能会发生指令重排,导致对象还没初始化完成,就返回了
//如果有两个线程在创建对象,可能会造成对象还没初始化完成,就返回了
//如果在创建对象时,多个线程同时判断到lazyMan==null,就会创建多个对象
//解决方法:
//1.使用synchronized关键字
//2.使用volatile关键字
}
}
}
return lazyMan;
}
//单线程下是安全的
//多线程下是不安全的,需要在加锁。
}
静态内部类
package com.lyc.single;
//静态内部类实现
public class Holder {
private Holder(){
}
public static Holder getInstance(){
return InnerClass.holder;
}
public static class InnerClass{
private static final Holder holder = new Holder();
}
}
单例不安全,因为有反射
枚举
package com.lyc.single;
import java.lang.reflect.Method;
//enum是什么,枚举本身也是一个Class类
public enum EnumSingle {
INSTANCE;
public EnumSingle getInstance() {
return INSTANCE;
}
}
package com.lyc.single;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class SingleTest {
public static void main(String[] args) throws Exception{
EnumSingle instance = EnumSingle.INSTANCE;
Constructor<EnumSingle> declaredConstructor = EnumSingle.class.getDeclaredConstructor(String.class, int.class);
declaredConstructor.setAccessible(true);
EnumSingle instance1 = declaredConstructor.newInstance();
System.out.println(instance.hashCode());
System.out.println(instance1.hashCode());
}
}