1 类图
2 饿汉式单例
例如:静态块、静态成员
2.1 概念
类加载的时候就立即初始化,并且创建单例对象
2.2 优点
没有加任何的锁、执行效率比较高
2.3 缺点
类加载的时候就初始化,不管用与不用都占着空间,浪费了内存。
3 懒汉式单例
3.1 直接:线程不安全
public class LazySimpleSingleton {
private LazySimpleSingleton(){}
//静态块,公共内存区域
private static LazySimpleSingleton lazy = null;
public static LazySimpleSingleton getInstance(){
if(lazy == null){
lazy = new LazySimpleSingleton();
}
return lazy;
}
}
3.2 同步方法
public class LazySimpleSingleton {
private LazySimpleSingleton(){}
//静态块,公共内存区域
private static LazySimpleSingleton lazy = null;
public synchronized static LazySimpleSingleton getInstance(){
if(lazy == null){
lazy = new LazySimpleSingleton();
}
return lazy;
}
}
3.2.1 优化CPU:双重检查锁
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指向刚分配的内存地址
//4.初次访问对象
}
}
}
return lazy;
}
}
3.2.2 IDEA 环境下的多线程调试
3.3 静态内部类
这种形式兼顾饿汉式的内存浪费,也兼顾synchronized性能问题,完美地屏蔽了这两个缺点
//史上最牛B的单例模式的实现方式
public class LazyInnerClassSingleton {
//默认使用LazyInnerClassGeneral的时候,会先初始化内部类
//如果没使用的话,内部类是不加载的
private LazyInnerClassSingleton(){
if(LazyHolder.LAZY != null){
throw new RuntimeException("不允许创建多个实例");
}
}
//每一个关键字都不是多余的
//static 是为了使单例的空间共享
//保证这个方法不会被重写,重载
public static final LazyInnerClassSingleton getInstance(){
//在返回结果以前,一定会先加载内部类
return LazyHolder.LAZY;
}
//默认不加载
private static class LazyHolder{
private static final LazyInnerClassSingleton LAZY = new LazyInnerClassSingleton();
}
}
3.3.1 反射破坏单例
在构造函数上抛出异常
private LazyInnerClassSingleton(){
if(LazyHolder.LAZY != null){
throw new RuntimeException("不允许创建多个实例");
}
}
3.3.2 序列化破坏单例
增加 readResolve()方法
public class SeriableSingleton implements Serializable {
public final static SeriableSingleton INSTANCE = new SeriableSingleton();
private SeriableSingleton(){}
public static SeriableSingleton getInstance(){
return INSTANCE;
}
private Object readResolve(){
return INSTANCE;
}
}
4 注册式单例
4.1 枚举式单例
利用jdk特性。具有线程安全、实例唯一(杜绝反序列化破坏单例)的特点。
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;
}
}
4.1.1 优点
线程安全、实例唯一
4.2 容器缓存写法
public class ContainerSingleton {
private ContainerSingleton(){}
private static Map<String,Object> ioc = new ConcurrentHashMap<String,Object>();
public static Object getInstance(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);
}
}
}
}
4.2.1 优点
对象方便管理、懒加载
4.2.2 缺点
不加上synchronized存在线程安全问题
5 ThreadLocal-线程单例
5.1 写法
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();
}
}
5.2 优点
保证在单个线程中是唯一