单例模式

单例模式的介绍

单例模式是一种比较常见的设计模式,但是想要在Java中用好单例模式并不简单。在整个系统中,单例类只能有一个实例对象,且需自行完成实例化,并始终对外提供同一实例对象。
在计算机系统中,线程池、缓存、日志对象、对话框、打印机、显卡的驱动程序对象常被设计成单例。

饿汉式的单例模式

public class Singleton {
     
    //在类加载的时候创建单例实例,私有,只供内部调用
    private static Singleton instance = new Singleton();
    //创建私有无参构造
    private Singleton(){
     }
    //静态工厂方法
    public static Singleton getInstance(){
     
        return instance;
    }
}
饿汉式的特点
1、名字来看就是类一旦加载,就把单例初始化完成,保证getInstance的时候,单例是已经存在的了
2、饿汉式天生就是属于线程安全的,可以直接用于多线程而不会出现线程安全的问题
3、因为饿汉式在开始类创建的时候就实例化一个静态的对象出来,对象在内存中,会占用一定的内存空间。
所以当你第一次调用的时候速度会非常的快,但是如果你不使用,他也会在内存中,比较浪费内存的空间

懒汉式的单例模式

public class Singleton {
     
   private Singleton(){
     }
   private static Singleton instance = null ;
   //静态方法工厂
    public static  Singleton getInstance(){
     
        //只有在第一次真正需要的时候才会去创建
        if (instance == null){
     
            instance = new Singleton();
        }
        //返回单例对象
        return instance;
    }
}

懒汉模式会在真正使用单例对象时才创建单例对象。但在多线程场景中,它是线程不安全的,并发环境下很可能出现多个Singleton实例,这显然不符合要求。以下都是对getInstance这个方法改造,保证了懒汉式单例的线程安全问题

在方法上加锁

public class Singleton {
     
   private Singleton(){
     }
   //只有第一次调用的时候才去加载
   private static Singleton1 instance = null ;
   //在方法上加上synchronized
    public static synchronized Singleton getInstance(){
     
        if (instance == null){
     
            instance = new Singleton();
        }
        //返回单例对象
        return instance;
    }
}
此种锁虽然保证了线程安全,但是每次都要去同步,会影响性能问题

双重校验锁

public class Singleton {
     
   private Singleton(){
     }
   //使用volatile关键字防止重排序,因为 new Instance()是一个非原子操作,可能创建一个不完整的实例
   private static volatile Singleton instance = null ;
   //静态方法工厂
    public static  Singleton getInstance(){
     
        //避免每次加锁,只有在第一次没有创建对象的时候才会加锁
        if (instance == null){
     
            //加锁,只允许一个线程进入
            synchronized (Singleton.class){
     
                //只创建一次对象
                if (instance == null){
     
                    instance = new Singleton();
                }
            }
        }
        //返回单例对象
        return instance;
    }
}
在getInstance中做了两次null检查,确保了只有第一次调用单例的时候才会做同步,
这样也是线程安全的,同时避免了每次都同步的性能损耗

私有静态内部类

// 私有静态内部类
public class Singleton {
     
    // 私有构造方法
    private Singleton(){
     }
    // 私有静态内部类
    private static class SingletonHolder {
     
       private static final Singleton instance = new Singleton();
    }
    public static Singleton getInstance(){
     
    	// 返回静态内部类中的静态字段
        return SingletonHolder.instance; 
    }   
}
既实现了线程安全,又避免了同步带来的性能影响

你可能感兴趣的:(设计模式,java)