单例模式认识

263 阅读2分钟

单例模式

顾名思义,就是表示单个实例(对象)的模式,一个类只能有一个对象

怎样实现单例模式

首先对象从何而来,对象是调用构造方法进行创建的,所有我们要控制构造方法

  • 私有化构造方法
  • 对外提供一个公共可访问的方法,返回该类对象
  • 提前准备一个私有化的静态的对象,保证唯一,且只能本类访问

饿汉模式

饿汉模式:提前准备好对象

public class HungryMode
{
    //提前准备好唯一对象,private避免外界直接访问,static保证独享唯一
    private static HungryMode instance = new HungryMode();

    //私有化构造方法
    private HungryMode(){}

    //提供公共可访问的方法,返回该类对象,static:无需对象,直接通过类名调用
    public static HungryMode getInstance(){
        return instance;
    }
}

懒汉模式

懒汉模式:需要时,创建对象

public class LazyMode
{
    //提前定义,但不创建对象,private避免外界直接访问,static保证独享唯一
    private static LazyMode instance;

    //私有化构造方法
    private LazyMode(){}

    //提供公共可访问的方法,返回该类对象,static:无需对象,直接通过类名调用
    public static LazyMode getInstance(){
        if(instance == null){
            instance = new LazyMode();
        }
        return instance;
    }
}

懒汉模式-线程安全问题

当多个线程同时访问时,懒汉模式可能会产生线程安全问题,我们可以通过同步锁机制来解决

public class LazyMode
{
    private static LazyMode instance;
    
    private LazyMode(){}
    
    public static synchronized LazyMode getInstance(){
        if(instance == null){
            instance = new LazyMode();
        }
        return instance;
    }
}

加入同步函数后线程安全问题解决了,但是每次获取对象都要判断锁,效率比较低

我们可以使用双重校验锁方式来解决效率问题

public class LazyMode
{
    private static LazyMode instance;
    
    private LazyMode(){}
    
    public static LazyMode getInstance(){
    	/*如果第一个线程获取到了单例的实例对象,
         * 后面的线程再获取实例的时候不需要进入同步代码块中了*/
        if(instance == null){
        	//同步代码块用的锁是单例的字节码文件对象,且只能用这个锁
            synchronized (LazyMode.class) {
                if (instance == null) {
                    instance = new LazyMode();
                }
            }
        }
        return instance;
    }
}