当前位置: 移动技术网 > IT编程>开发语言>Java > 说说单例模式!

说说单例模式!

2020年07月29日  | 移动技术网IT编程  | 我要评论

单例模式

定义

确保一个类只有一个实例,并且提供该实例的全局访问点,就是这个类只能被new一次,并且每次都是用的new的这个。

类结构

一个私有的构造方法,一个私有的静态的实例变量,一个公有的静态函数,用来获取实例。

私有构造方法:可以不让别人创建

共有的静态函数:该实例的全局访问点,返回唯一的私有的静态实例变量

具体实现

懒汉式-线程不安全

懒汉式就是用到的时候才创建返回对象,不用到的时候不会创建,但也存在线程不安全的问题

线程不安全:多个线程同时第一次访问获取对象,都判断为空,然后都new了对象,导致多次实例化对象

public class Singleton {

    private static Singleton uniqueInstance;

    private Singleton(){

    }

    public static Singleton getUniqueInstance(){
        if (uniqueInstance == null){
            uniqueInstance = new Singleton();
        }
        return uniqueInstance;
    }
}
懒汉式-线程安全

如何解决懒汉式的线程不安全问题呢?使其变为线程安全的,只需要在获取实例的时候加锁就行,这样同一时间只能有一个线程进入获取实例的方法,就可以避免线程不安全问题了!

缺点:由于加锁了,导致同一时间只能有一个线程访问这个方法,有性能问题,不建议使用。

public static synchronized Singleton getUniqueInstance(){
        if (uniqueInstance == null){
            uniqueInstance = new Singleton();
        }
        return uniqueInstance;
    }
饿汉式-线程安全

也是为了解决懒汉式的线程不安全问题,直接实例化就行,不再使用延迟实例化,但是没有延迟实例化能节约资源

public class Singleton {

    private static Singleton uniqueInstance = new Singleton();

    private Singleton(){

    }

    public static synchronized Singleton getUniqueInstance(){
        return uniqueInstance;
    }
}
双重校验锁-线程安全

就是在实例化的时候进行加锁即可,不在方法上进行加锁了

public class Singleton {

    private volatile static Singleton uniqueInstance;

    private Singleton(){

    }

    public static  Singleton getUniqueInstance(){
        if (uniqueInstance == null){
            synchronized (Singleton.class){
                if (uniqueInstance == null){
                    uniqueInstance = new Singleton();
                }
            }
        }
        return uniqueInstance;
    }
}

首先解释为什么用volatile关键字

禁止jvm的指令重排,首先实例化一个对象分为三个步骤

  1. 分配内存空间
  2. 初始化对象
  3. 将对象指向分配的内存地址

这个顺序在jvm中执行式有可能乱序的,比如会132这样执行,当一个线程执行完成13之后,另一个线程刚好进入if判断不为空,直接就返回了一个未初始化的对象,所以为了解决这个问题使用volatile关键字可以禁止指令重排

再解释为什么用两个if

当两个线程同时进入第一个if,都判断不为空,然后上锁,一个线程进行实例化对象操作,实例化完毕后,另一个线程也加锁进入,但是如果没有第二个if的话,第二个进程还会进行实例化,加上之后就不会进行第二次实例化了。

静态内部类实现-线程安全

就是使用一个静态内部类,类中写一个静态常量,Singleton类被加载的时候并不会调用内部类,只有需要获取实例的时候才会调用内部类进行获取。

实现了延迟实例化+线程安全

public class Singleton {

    private Singleton(){

    }

    private static class SingletonHolder{
        private static final Singleton INSTANCE = new Singleton();
    }

    public static  Singleton getUniqueInstance(){
        return SingletonHolder.INSTANCE;
    }
}

本文地址:https://blog.csdn.net/hsunnyc/article/details/107618315

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网