不要急,不要急,马上好^_^...

单例模式


单例模式

特点:

  1. 在JVM中,单例模式能保证对象实例只有一个
  2. 构造器必须是私有的,外部无法通过构造器创建对象实例
  3. 没有公开的set方法,外部不能通过set方法进行对象的创建
  4. 对外公开提供一个get方法,通过get方法可以获取对象实例

优点:

  1. 某些类创建非常繁琐,使用单例模式避免对象的频繁创建,而造成性能损耗
  2. 省去了new操作符,减轻系统内存使用频率,减轻GC的压力
  3. 避免对资源的重复占用

饿汉式单例模式

public class Singleton{
    private static Singleton instance = new Singleton();
    private Singleton(){};
    public static Singleton getInstance(){
        return instance;
    }
}

为什么说是饿汉式呢?

​ 因为它在类加载的时候就直接把实例创建了出来,后面的方法直接进行返回即可

应用场景:

​ 适用于热点数据,在启动JVM的时候,就将热点数据创建好,这样也可以避免预热阶段,直接就可以使用了。

为什么是线程安全的?

​ 因为类加载的方式是按需加载,且只加载一次,因此在访问单例对象的时候,其实单例对象的实例已经创建好了。因此饿汉式天生就是线程安全的。

懒汉式单例模式

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

懒汉式单例模式是非线程安全的

为什么叫懒汉式呢?

​ 因为类加载的时候,并不会直接将这个实例创建出来,而是在需要使用的时候进行创建

使用场景

​ 适用于那些不热门的数据,因为只有在需要使用的时候进行调用并创建,这样就不会造成不必要的空间浪费

为什么是非线程安全的呢?

​ 这里假设有两个线程,第一个线程和第二个线程现在都进行了if的判断,进入到了对象的创建,那么这两个线程就会创建两个对象。

那么针对这个懒汉式的非线程安全使用下面加锁的方式进行解决

懒汉式加锁

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

这样直接在获取对象实例的方法上加锁,虽然保证了线程的安全,但是这样加锁性能太低了,那么如何解决呢???

懒汉式加锁进阶

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

这样把锁加在方法内,而且进行了一次判断,这样性能比上一个性能有提高,但是JVM对代码的运行会有运行优化,也就是在运行期间会进行指令重排操作,意思就是比如现在一个线程已经创建好了实例,而且JVM内存中也开辟了空间给这个实例,但是还没有初始化完成,而这个时候另一个线程判断instance不为空,那么直接返回进行调用,发现还没有实例化而出现错误,那么又如何解决这个问题呢???

懒汉式加锁进阶加强(volatile)

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

volatile主要是防止代码运行时的指令重排,可以保证,在创建实例完成,并且初始化之后,另外的线程才能对实例进行使用,那么这个已经很完美了,但是还有比这个更好的方式进行实现吗??

基于静态内部类实现的单例模式

public class Singleton{
	private Singleton(){}
    
    private static class SingletonFactory{
        private static Singleton instance = new Singleton();
    }
    
    public static Singleton getInstance(){
        return SingletonFactory.instance;
    }
}

基于枚举的单例模式

class enum Singleton{
	Instance;
}

为什么使用单例模式而不使用静态类呢?

  1. 单例模式有懒汉模式,可以按需进行资源加载,而静态类会直接加载进内存中
  2. 静态类每次创建使用之后,都会被GC掉,而单例对象不会被GC

文章作者: Mr Hou
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Mr Hou !
希望得到你的建议哦
  目录