单例模式的意义
- 表示全局的唯一(配置类、全局计数器)
- 处理资源访问冲突
不同方式实现单例
单例通用构造形式
● 构造器私有化
● 提供对外接口
饿汉式
● 当类加载好的情况下就已经创建好单例,线程创建过程是安全的
● 不需要使用也会被加载,浪费内存资源
java
public class EagerSingleton {
private static EagerSingleton singleton=new EagerSingleton();
private EagerSingleton() {
}
EagerSingleton getInstance(){
return singleton;
}
}
懒汉式
● 需要才会被创建加载,延迟加载
● 高并发场景下,无法保证单例的特点(通过加关键字synchronized解决)
java
public class LazySingleton {
private LazySingleton instance=null;
private LazySingleton() {
}
LazySingleton getInstance(){
if(instance==null){
instance=new LazySingleton();
}
return instance;
}
/**
* 简单的线程安全版(获得锁的时候是线程安全的)
* 但是会降低很多并发度,实际上我们想要的是创建锁的时候线程安全 引申出双重检查锁版
*/
public synchronized LazySingleton getInstance(){
if(instance==null){
instance=new LazySingleton();
}
return instance;
}
}
双重检查锁
● 支持延迟加载,线程安全的实现
java
public class DclSingleton {
private DclSingleton instance=null;
private DclSingleton() {
}
DclSingleton getInstance(){
if(instance==null){
synchronized (DclSingleton.class){
if(instance==null){
instance=new DclSingleton();
}
}
}
return instance;
}
}
静态内部类的实现
● 与双重检测锁一样的效果,但是通过静态内部类实现,比较简单
java
/**
* 静态内部类实现单例模式
*/
public class InnerSingleton {
private InnerSingleton(){
}
public InnerSingleton getInstance(){
return SingletonHolder.instance;
}
/**
* 当外部类被加载的时候,静态内部类不会被加载
* 只有调用getInstance,SingletonHolder 才会被加载,才会创建单例
*/
static class SingletonHolder{
private static final InnerSingleton instance=new InnerSingleton();
}
}
枚举
● 枚举特性就是保证了唯一性和线程安全性,实现相对比较简单
java
public enum GlobalCounter {
INSTANCE;
private AtomicInteger atomicInteger=new AtomicInteger(0);
public long getNumber(){
return atomicInteger.incrementAndGet();
}
}
单例模式破坏
● 反射入侵(通过反射得到构造器,再创建实例)
● 序列化与反序列化(会破坏单例特点)
源码应用
JDK中的Runtime.class
单例存在的问题
- 无法支持面向对象编程(OOP 的三大特性是封装、继承、多态。单例将构造私有化,直接导致的 结果就是,他无法成为其他类的父类,这就相当于直接放弃了继承和多态的特性。
- 极难的拓展性(业务拓展,单例逐渐需要变得多例,比如数据库连接池可能根据数据库的类型不同有不同的连接池)
不同作用范围下的单例
线程级别的单例
● 单例一般是进程级别的,实现一个线程级别的单例几个思路
● TheardLocal就是线程级别的单例,保持每个线程独立,可以再里面进行读写东西
● spring中的RequestContextHolder,可以再一个线程中轻松的获取 request、response和session。
容器级别的单例
● 从进程切换到一个容器管理,利用spring强大的容器管理对象的整个生命周期,确保单例的特点