饿汉式
优点:线程安全,没加锁,执行效率高
缺点:类加载时就初始化,用没用都占着资源
public class HungrySingleton implements Serializable {
// 先静态后动态
//先属性后方法
//先上后下
public static final HungrySingleton hungrySingleton = new HungrySingleton();
private HungrySingleton() {
}
public static HungrySingleton getInstance() {
return hungrySingleton;
}
private Object readResolve() {
return hungrySingleton;
}
}
懒汉式
使用双端检查减少加锁频率,提高效率
public class LazyDoubleCheckSingleton {
private volatile static LazyDoubleCheckSingleton lazy = null;
private LazyDoubleCheckSingleton(){}
public static LazyDoubleCheckSingleton getInstance() {
if (lazy == null) {
synchronized (LazyDoubleCheckSingleton.class) {
if (lazy == null) {
lazy = new LazyDoubleCheckSingleton();
// 1.分配内存给对象
// 2. 初始化对象
// 3. 设置lazy指向刚分配的内存
}
}
}
return lazy;
}
}
内部类
// 解决饿汉式浪费性能,懒汉加锁的问题
public class LazyInnerClassSingleton {
// 如果使用LazyInnerClassSingleton的话会默认先加载内部类
// 如果没有使用,是不会加载的
private LazyInnerClassSingleton(){
if (LazyHolder.LAZY != null) {
throw new RuntimeException("不允许创建多个实例");
}
}
// static 使单例空间共享, final使这个方法不会被重写,重载
public static final LazyInnerClassSingleton getInstance() {
// 返回结果之前,一定会先加载内部类
return LazyHolder.LAZY;
}
// 默认不加载
private static class LazyHolder{
private static final LazyInnerClassSingleton LAZY = new LazyInnerClassSingleton();
}
}
反射破坏单例
@Test
public void testLazyInnerClassSingleton() {
try {
Class<?> clazz = LazyInnerClassSingleton.class;
Constructor<?> c = clazz.getDeclaredConstructor(null);
c.setAccessible(true);
Object o1 = c.newInstance();
Object o2 = c.newInstance();
System.out.println(o1 == o2);
} catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
}
输出:true
序列化破坏单例
@Test
public void testSeriableSingletonTest() {
HungrySingleton h1 = null;
HungrySingleton h2 = HungrySingleton.getInstance();
FileOutputStream fos = null;
try {
fos = new FileOutputStream("HungrySingleton.obj");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(h2);
oos.flush();
oos.close();
FileInputStream fis = new FileInputStream("HungrySingleton.obj");
ObjectInputStream ois = new ObjectInputStream(fis);
h1 = (HungrySingleton) ois.readObject();
ois.close();
System.out.println(h1);
System.out.println(h2);
System.out.println(h1 == h2);
} catch (Exception e) {
e.printStackTrace();
}
}
输出:true
枚举单例
优点:不会被序列化和反射破坏单例
public enum EnumSingleton {
INSTANCE;
private Object data;
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
// 可不要
public static EnumSingleton getInstance() {
return INSTANCE;
}
}
容器式单例
public class ContainerSingleton {
private ContainerSingleton() {}
private static Map<String, Object> ioc = new ConcurrentHashMap<>();
private 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;
} else {
return ioc.get(className);
}
}
}
}