1.1、概念
定义:确保一个类只有一个实例,且自动实例化并向整个系统提供这个实例
特点:
成员变量:private static final
构造函数私有化
只提供getInstance()方法获取对象实例
1.2、应用
1.2.1、优缺点
-
优点:
- 减少内存开支
- 减少系统性能消耗
- 避免对资源的多重占用(多个实例写同一个文件)
- 设置全局的访问点,优化和共享资源访问
-
缺点:
- 没有接口,扩展困难
- 对测试不利
- 与单一职责原则有冲突(单一职责原则要求一个类应该只实现一个逻辑)
1.2.2、使用场景
- 生成唯一序列号的环境
- 需要一个共享访问点或共享数据
- 创建一个对象需要消耗的资源过多
- 需要定义大量的静态厂里和静态方法
1.3、单例模式的实现方式(五种)
1.3.1、饿汉式单例
public class Singleton{
private static final Singleton singleton=new Singleton();
private Singleton(){}
public static Singleton getInstance(){
return singleton;
}
}
类的加载时就会实例化,且只加载一次,只传创建一个实例
优点:写法简单,避免线程问题
缺点:如果始终没有用过这个实例,就会造成内存浪费
1.3.2、懒汉式单例
public class Singleton{
private static Singleton singleton=null;
private Singleton(){}
public static Singleton getInstance(){
if(this.singleton==null){
this.singleton=new singleton();
}
return singleton;
}
}
单例被延迟加载,只有使用的时候才会实例化
注意:懒汉式单例在高并发的情况下会出现多个实例的情况
描述:高并发下,当一个线程A执行到 this.singleton=new singleton(); ,但还没有获取对象时(对象初始化需要时间),第二个线程B执行到 if(this.singleton==null) 判断,那么线程B获得判断条件也是为真,于是两个线程都获得了对象,内存中就出现了两个对象。
优点:懒加载,避免内存浪费
缺点:线程安全问题
1.3.3、双重锁式单例
//解决线程安全问题,增加Synchronized
public class Singleton{
private static Singleton singleton=null;
private Singleton(){}
public static Singleton getInstance(){
//先判断是否存在,不存在再加锁处理
if(this.singleton==null){
//在同一个时刻加了锁的那部分程序只有一个线程可以进入
synchronized(Singletonc.class){
if(this.singleton==null){
this.singleton=new singleton();
}
}
}
return singleton;
}
}
综合了懒汉式和饿汉式两者的优缺点整合而成。既保证了线程安全,又比直接上锁提高了执行效率,还节省了内存空间。
1.3.4、静态内部类(最推荐使用)
public class Singleton {
private Singleton() {}
private static class SingletonInstance {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonInstance.INSTANCE;
}
}
与双重锁类似,但实现更简单。只有在调用 getInstance()时才会实例化。
1.3.5、枚举单例(不常用)
public enum Singleton {
INSTANCE;
//可以getInstance方法,通过Singleton.INSTANCE进行操作
}
1.4、扩展:有上限的多例模式
要求一个类只能产生有限个数的实例对象
public class Singleton{
//定义最多能产生的实例数量
private static int maxNum=3;
//定义一个List,存放实例
private static List<Singleton> singletonList=new ArrayList<Singleton>();
static{
for(int i=0:i<maxNum;i++){
singletonList.add(new Singleton())
}
}
private Singleton(){}
public static Singleton getInstance(){
//随机获取一个实例
Random random=new Random();
return singletonList.get(random.nextInt(maxNum));
}
}