单例模式
确保一个类只有一个实例,并提供一个全局访问点
单例模式的使用场景:线程池、缓存、对话框、处理偏好设置、注册表的对象、日志对象、充当打印机、显卡等设备的驱动程序的对象
基本方法
在一个A类中
- 创建一个静态变量来记录A类的唯一实例
- 将构造器声明为私有类,只有A类内才能调用
- 使用getInstance()方法实例化对象,并返回这个对象
public classs Singleton{
//用来记录Singleton类唯一的实例化
private static Singleton uniqueInstance;
//私有构造器
private Singleton(){}
//实例化对象,并返回对象
public static Singleton getInstance(){
if(uniqueInstance==null){
uniqueInstance=new Singleton();
}
return uniqueInstance;
}
}
注意:在有多个线程执行这段代码时,会扰乱这段代码,会产生不同的实例对象
解决方法:
1、使用同步关键字synchronize解决多线程的问题
public classs Singleton{
private static Singleton uniqueInstance;
private Singleton(){};
public static synchronize Singleton getInstance(){
if(uniqueInstance==null){
uniqueInstance=new Singleton();
}
return uniqueInstance;
}
}
只有第一次执行次方法时,才真正需要同步。如果使用同步关键字,那么当我们实例化变量后,之后调用此方法时都会进行同步处理。同步一个方法可能会造成程序的执行效率下降100倍,如果它会频繁的运行,我们就需要考虑其他方法了。
2、在加载类时直接实例对象,马上创建唯一的单件实例
public classs Singleton{
private static Singleton uniqueInstance=new Singleton();
private Singleton(){}
public static Singleton getInstance(){
return uniqueInstance;
}
}
3、用“双重检测加锁”,在getInstance()中减少使用同步
在代码中我们会首先检测实例是否创建,如果未创建,我们才进入同步。
public classs Singleton{
//volatile防止指令重排,多个线程正确地处理变量
private volatile static Singleton uniqueInstance;
private Singleton(){}
public static Singleton getInstance(){
//检测实例,如果不存在则进入同步区块
if(uniqueInstance==null){
synchronized(Singleton.class){
if(uniqueInstance==null){
uniqueInstance=new Singleton();
}
}
}
return uniqueInstance;
}
}