我们知道Java里边共有23种设计模式,单例模式是经常出现的一种设计模式,也是经典的高频面试题,他属于创建型设计模式。
单例模式
定义:
是指一个类在任何情况下有且仅有一个实例,并提供一个全局访问点。
适用场景:
确保任何情况下都仅有一个实例(ServletContext、ServletConfig、ApplicationContext)
优点:
(1) 内存中只有一个实例,减少内存开销。
(2) 避免对资源的多重占用。
(3) 设置全局访问点,严格控制访问。
缺点:
(1) 没有接口,扩展困难。
(2) 如果要扩展单例对象,只有修改代码。
实例:
(1) 饿汉式单例
/**
* 优点:执行效率高,没有任何的锁
* 缺点:某些情况下内存浪费
*/
public class HungrySingleton {
private static final HungrySingleton singleton = new HungrySingleton();
private HungrySingleton() {}
public static HungrySingleton getInstance() {
return singleton;
}
}
/**
* 优点:执行效率高,没有任何的锁
* 缺点:某些情况下内存浪费
*/
public class HungryStaticSingleton {
private static final HungryStaticSingleton singleton;
static {
singleton = new HungryStaticSingleton();
}
private HungryStaticSingleton() {}
public static HungryStaticSingleton getInstance() {
return singleton;
}
}
(2) 懒汉式单例
/**
* 优点:节约内存
* 缺点:线程不安全
*/
public class LazySingleton {
private static LazySingleton lazySingleton;
private LazySingleton() {}
public static LazySingleton getInstance() {
if(lazySingleton == null){
lazySingleton = new LazySingleton();
}
return lazySingleton;
}
}
/**
* 优点:节约内存,线程安全
* 缺点:性能受限
*/
public class LazySingleton {
private static LazySingleton lazySingleton;
private LazySingleton() {}
public static synchronized LazySingleton getInstance() {
if(lazySingleton == null){
lazySingleton = new LazySingleton();
}
return lazySingleton;
}
}
/**
* 优点:性能高,线程安全
* 缺点:可读性变差
*/
public class DoubleCheckSingleton {
private volatile static DoubleCheckSingleton singleton;
private DoubleCheckSingleton() {}
public static DoubleCheckSingleton getInstance() {
//是否需要阻塞,减小锁的粒度
if(singleton == null){
synchronized (DoubleCheckSingleton.class) {
//是否需要重新创建实例
if(singleton == null){
//存在指令重排序问题(多线程下引用和实例创建的先后顺序)
singleton = new DoubleCheckSingleton();
}
}
}
return singleton;
}
}
/**
* 优点:延时加载,利用Java本身语法特性
* 缺点:以上都可以被反射破坏(获取私有构造函数)
*/
public class LazySingleton {
private LazySingleton() {
if(LazyHolder.singleton != null){//避免被反射破坏
throw new RuntimeException("不允许非法访问");
}
}
private static class LazyHolder {
private static final LazySingleton singleton = new LazySingleton();
}
public static LazySingleton getInstance(){
return LazyHolder.singleton;
}
}
扩展 -- 反射破坏单例代码
/**
* 反射类
*/
public class ReflectTest {
public static void main(String[] args) {
Class<?> clazz = LazySingleton.class;
//反射获取私有构造方法
Constructor constructor = clazz.getDeclaredConstructor(null);
constructor.setAccessible(true);
Object o1 = constructor.newInstance();
Object o2 = constructor.newInstance();
System.out.println(o1 == o2);
}
}
(3) 注册式单例
/**
* 枚举式单例 从官方层面,可以避免反射破坏单例
*/
public enum EnumSingleton {
INSTANCE;
public static EnumSingleton getInstance(){
return INSTANCE;
}
}
/**
* 容器式单例 基于枚举式单例改进
*/
public class ContainerSingleton {
private ContainerSingleton() {}
private static Map<String, Object> ioc = new ConcurrentHashMap<String, Object>();
public static Object getInstance(String clazzName) {
try {
//利用ConcurrentHashMap#putIfAbsent()方法实现原子性
ioc.putIfAbsent(clazzName, Class.forName(clazzName).newInstance());
} catch (Exception e) {
e.printStackTrace();
}
return ioc.get(clazzName);
}
}
扩展 -- 序列化和反序列化破坏单例代码
/**
* 序列化 把内存中的对象转为字节码形式,在通过IO输出流写到磁盘上
* 反序列化 将持久化的字节码内容通过IO输入流读到内存中,转化成Java对象
*/
public class SeriableSingleton implements Serializable {
private final static SeriableSingleton singleton = new SeriableSingleton();
private SeriableSingleton() {}
public static SeriableSingleton getInstance() {
return singleton;
}
//解决序列化和反序列化破坏单例
private Object readResolve() {
return singleton;
}
}
扩展 -- 序列化和反序列化代码
/**
* 序列化和反序列化代码
*/
public class SeriableSingletonTest {
public static void main(String[] args) {
try {
//序列化到磁盘
SeriableSingleton o2 = SeriableSingleton.getInstance();
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("SeriableSingleton.obj"));
oos.writeObject(o2);
oos.flush();
oos.close();
//反序列化成Java对象
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("SeriableSingleton.obj"));
SeriableSingleton o1 = (SeriableSingleton) ois.readObject();//查看readResolve方法(反射创建对象)
ois.close();
System.out.println(o1 == o2);
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* ThreadLocal单例 保证线程内部的全局唯一
*/
public class ThreadLocalSingleton {
private ThreadLocalSingleton() {}
private static final ThreadLocal<ThreadLocalSingleton> threadLocalSingleton = new ThreadLocal<ThreadLocalSingleton>() {
@Override
protected ThreadLocalSingleton initialValue() {
return new ThreadLocalSingleton();
}
};
public static ThreadLocalSingleton getInstance() {
return threadLocalSingleton.get();//以当前对象所在的线程作为ThreadLocalMap的key,来实现线程隔离
}
}