-确保一个类在任何情况下都绝对只有一个实例,并提供一个全局的访问点-
-隐藏其所有的构造方法
-属于创建型模式
(例如:servletContext、ServletConfig、ApplicationContext)
单例模式常见写法:
1 饿汉式单例
在单例内首次加载就创建实例
public class HungrySingleton{
private static final HungrySingleton hungrySingleton = new HungrySingleton();
private HungrySingleton(){
}
public static HungrySingleton getInstance(){
return hungrySingleton;
}
}
缺点:浪费内存空间(不管使不使用、都会创建实例)
2 懒汉式单例
public class LazySingleton{
// volatile 解决重排序问题
private volatile static LazySingleton lazySingleton= null;
private LazySingleton(){
}
// 多线程情况下,不能保证单例,或者存在覆盖
1.public static LazySingleton getInstance(){
if(lazySingleton == null){
lazySingleton = new LazySingleton ()
}
return lazySingleton;
}
// 可能存在性能问题
2.public synchronized static LazySingleton getInstance(){
if(lazySingleton == null){
lazySingleton = new LazySingleton ()
}
return lazySingleton;
}
// 双重判断加锁
3.public static LazySingleton getInstance(){
if(lazySingleton == null){
synchronized (LazySingleton.class){、
if(lazySingleton == null){
lazySingleton = new LazySingleton ();
//cpu执行的时候会转换成JVM指令
// 指令重排序的问题,volatile
// 1、分配内存给对象
// 2、初始化对象
// 3、将初始化好的对象和内存地址建立关联,赋值
// 4、用户初次访问
}
}
}
return lazySingleton;
}
}
4.静态内部类方式实现(性能最优实现)
public class LazyInnerClassSingleton{
// 可通过反射获取实例,则有可能存在多个实例
private LazyInnerClassSingleton(){
// 解决反射-如果想通过反射,则直接抛出异常
if( LazyHolder.lazy ! = null){
throw new RuntimeException("不允许构建多个实例");
}
}
public static final LazyInnerClassSingleton getInstance(){\
return LazyHolder.lazy ;
}
// 内部类的内容需要在外部调用时才会执行
private static class LazyHolder{
private static final LazyInnerClassSingleton lazy = new LazyInnerClassSingleton();
}
}
--仍然有可能通过序列破坏单例
// 解决,源码hasReadResolve方法会判断,有则直接由单例代替新创建的对象
// 重写readResolve 。还是创建了两次对象,新创建对象会被GC
private Object readResolve(){
return 单例对象
}
3 注册式单例
1.枚举式单例 jdk层面保证了单例
public enum EnumSingleton{
INSTANCE;
private Object data;
// 省略get set
public static EnumSingleton getInstance(){
return INSTANCE;
}
}
2.容器式单例(例如springioc 方便管理单例对象)
// 存在线程安全问题 可通加锁解决
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)){
obj = Class.forName(className).newInstance();
ioc.put(className,obj);
}
return ioc.get(className);
}
}
}
4 ThreadLocal单例
// 伪线程安全 同一个线程内单例。不同线程则是不同实例
// 如orm实现多数据源动态切换
public class TheadLocalSingleton{
public TheadLocalSingleton(){}
private static final ThreadLocal<TheadLocalSingleton> threadLocalInstance =
new ThreadLocal<TheadLocalSingleton>(){
protected TheadLocalSingleton initialValue(){
return new TheadLocalSingleton();
}
}
public static TheadLocalSingleton getInstance(){
return threadLocalInstance.get();
}
}
-- 单例缺点:扩展性不强,扩展需要更改代码。
设计单例模式需要思考的:
1,私有化构造器
2.保证线程安全
3.延迟加载
4.防止序列化和反序列化破坏单例
5.防御反射攻击单例