单例模式的使用场景
- 有频繁实例化然后销毁的情况,也就是频繁的new对象
- 创建对象时耗时过多或耗资源过多,但又经常用到的对象
- 频繁访问IO资源的对象,比如数据库连接池或访问本地文件
1.饿汉模式
public class Singleton{
private static Singleton instance = new Singleton();
private Singleton(){
}
public static Singleton getInstance(){
return instance;
}
}
2.不使用同步锁(懒汉模式)
public final class Singleton{
private static Singleton instance = null;
private Singleton(){
}
public static Singleton getInstance(){
if(instance == null)
instance = new Singleton();
return instance;
}
}
3.使用同步方法
public class Singleton{
private static Singleton instance;
private Singleton(){
}
public static synchronized Singleton getInstance(){
if(instance == null)
instance = new Singleton();
return instance;
}
}
- 同步的代价必然会一定程度的使程序的并发度降低
- 因此需将同步的粒度降低
4.使用双重锁
public class Singleton{
private volatile static Singleton instance;
private Singleton(){
}
public static Singleton getInstance(){
if(instance == null){
synchronized(Singleton.class){
if(instance == null)
instance = new Singleton();
}
}
return instance;
}
}
- **该方法的弊端是可能会得到没被完整初始化的对象! 得到一个没有初始化完全的对象并没有作用
- 线程A在创建单例对象时,在构造方法被调用之前,就为该对象分配了内存空间并将对象的字段设置为默认值。此时线程A就可以将分配的内存地址赋值给instance字段了,然而该对象可能还没有初始化。线程B来调用newInstance()方法,得到是未初始化完全的单例对象,这就会导致系统出现异常行为。
- 因此需要加上volatile 禁止指令重排,保证代码的有序性**
5.使用static代码块
public class Singleton{
private static Singleton instance = null;
private Singleton(){
}
static{
instance = new Singleton();
}
public static Singleton getInstance(){
return instance;
}
}
6.静态内部类
- 使用jvm的机制进行同步保证,没有一个同步的关键字
public class Singleton{
private static class Singleton{
private static final Singleton instance = new Singleton();
}
public static Singeleton getInstance(){
return Singleton.instance;
}
}
7.枚举方式(枚举类被暴露,违背职责单一原则)
public enum SingleEnum{
INSTANCE;
private Singleton instance;
private SingleEnum(){
instance = new Singleton();
}
public Singleton getInstance(){
return instance;
}
}
class Singleton{
public Singleton(){
}
}
- 我们可以通过 SingleEnum.INSTANCE.getInstance() 来访问实例。而且创建枚举默认就是线程安全的,并且还能防止反序列化导致重新创建新的对象。
8.枚举方式的完善
public class Factory{
public enum SingleEnum{
INSTANCE;
private Singleton instance;
private SingleEnum(){
instance = new Singleton();
}
public static Singleton getInstance(){
return instance;
}
}
public static Singleton getInstance(){
return SingleEnum.INSTANCE.getInstance();
}
}
class Singleton{
public Singleton(){
}
}