单例模式的几种用法
1、饿汉式单例
package com.singleton;
/**
* @author: RenKaiQi
* @date: 2021/4/6 13:04
* @description: 饿汉式单例 缺点:内存浪费
*/
public class HungrySingleton {
private static HungrySingleton hungrySingleton = new HungrySingleton();
/*static {
hungrySingle = new HungrySingle();
}*/
private HungrySingleton(){}
public static HungrySingleton getInstance(){
return hungrySingleton;
}
}
2、懒汉式单例
package com.singleton;
/**
* @author: RenKaiQi
* @date: 2021/4/6 13:07
* @description: 懒汉式单例 缺点:synchronized 性能问题
*/
public class LazySingleton {
private static LazySingleton lazySingleton = null;
private LazySingleton(){}
/**
* 原始
* @return
*/
public static synchronized LazySingleton getInstance(){
if(lazySingleton ==null){
lazySingleton = new LazySingleton();
}
return lazySingleton;
}
/**
* 双重校验优化后的方法
* lazySingleton属性要加上volatile关键字修饰
* @return
*/
public static LazySingleton getInstance2(){
if(lazySingleton ==null){
synchronized (LazySingleton.class){
if(lazySingleton ==null) {
lazySingleton = new LazySingleton();
}
}
}
return lazySingleton;
}
}
3、静态内部类的方式
package com.singleton;
import java.io.Serializable;
/**
* @author: RenKaiQi
* @date: 2021/4/6 13:16
* @description: 使用内部类 调用getInstance方法时返回一定会先加载内部类 优点:兼顾饿汉式内存浪费 以及synchronized性能问题
*/
public class InnerClassSingleton implements Serializable {
public static final InnerClassSingleton getInstance(){
return InnerClass.LAZY;
}
private InnerClassSingleton(){
// 防止反射破化单例
if(InnerClass.LAZY != null){
throw new RuntimeException("不可反射创建");
}
}
/**
* 防止序列化破坏单例 加上这个方法private Object readResolve()
* readResolve()方法底层还是创建了新的对象,只是新对象没有被返回还是会产生内存分配的问题
*
* @return
*/
private Object readResolve(){
return InnerClass.LAZY;
}
//当前类有引用内部类时一定会先加载内部类
private static class InnerClass{
private static final InnerClassSingleton LAZY = new InnerClassSingleton();
}
}
4、注册式单例(枚举)
package com.singleton;
/**
* @author: RenKaiQi
* @date: 2021/4/6 16:17
* @description: 注册式单例 使用优雅,是最推荐的一种写法。
* 缺点:但是跟饿汉式单例一样,在类加载时就会将对象初始化,不适合创建大量单例对象的场景
*/
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;
}
}
5、容器式单例
package com.singleton;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author: RenKaiQi
* @date: 2021/4/6 16:44
* @description: 容器式单例 类似于Spring ioc
*/
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)) {
try {
Class<?> clazz = Class.forName(className);
Object obj = clazz.newInstance();
ioc.put(className, obj);
return obj;
} catch (Exception e) {
e.printStackTrace();
}
}
}
return ioc.get(className);
}
}
6、ThreadLocal实现线程单例
package com.singleton;
/**
* @author: RenKaiQi
* @date: 2021/4/6 17:02
* @description: 线程单例
* ThreadLocal不能保证其创建的对象式全局唯一的,但是能保证在单个线程中是唯一的,天生是线程安全的
*/
public class ThreadLocalSingleton {
private static final ThreadLocal<ThreadLocalSingleton> threadLocalInstance =
new ThreadLocal<ThreadLocalSingleton>() {
@Override
protected ThreadLocalSingleton initialValue() {
return new ThreadLocalSingleton();
}
};
private ThreadLocalSingleton() {}
public static ThreadLocalSingleton getInstance() {
return threadLocalInstance.get();
}
}
测试代码:
package com.singleton;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
/**
* @author: RenKaiQi
* @date: 2021/4/6 15:37
* @description:
*/
public class SingletonTest {
public static void main(String[] args) {
// 反射破坏单例
/*Class<InnerClassSingle> clazz = InnerClassSingle.class;
try {
Constructor<InnerClassSingle> constructor = clazz.getDeclaredConstructor();
constructor.setAccessible(true);
InnerClassSingle innerClassSingle1 = constructor.newInstance();
System.out.println(innerClassSingle1);
InnerClassSingle innerClassSingle2 = constructor.newInstance();
System.out.println(innerClassSingle2);
} catch (Exception e) {
e.printStackTrace();
}*/
// 序列化破坏单例
/*InnerClassSingleton instance1 = InnerClassSingleton.getInstance();
InnerClassSingleton instance2 = null;
try {
FileOutputStream fileOutputStream = new FileOutputStream("InnerClassSingle.obj");
ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
objectOutputStream.writeObject(instance1);
objectOutputStream.flush();
objectOutputStream.close();
FileInputStream fileInputStream = new FileInputStream("InnerClassSingle.obj");
ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
instance2 = (InnerClassSingleton) objectInputStream.readObject();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(instance1);
System.out.println(instance2);*/
// 注册式单例测试
EnumSingleton enumSingleton1 = EnumSingleton.getInstance();
enumSingleton1.setData(new Object());
EnumSingleton enumSingleton2 = null;
EnumSingleton enumSingleton3 = EnumSingleton.getInstance();
enumSingleton3.setData(new Object());
try {
FileOutputStream fileOutputStream = new FileOutputStream("Object.obj");
ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
objectOutputStream.writeObject(enumSingleton1);
FileInputStream fileInputStream = new FileInputStream("Object.obj");
ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
enumSingleton2 = (EnumSingleton) objectInputStream.readObject();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(enumSingleton1 == enumSingleton2); // true
System.out.println(enumSingleton1 == enumSingleton3); // true
System.out.println(enumSingleton2 == enumSingleton3); // true
}
}