栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

单例模式知识点

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

单例模式知识点

定义

Java中单例模式定义:“一个类有且仅有一个实例,并且自行实例化向整个系统提供。”

单例模式的实现主要依托static关键字。

单例模式的两种类型

1.饿汉模式:实例的创建出现在类加载阶段;
2.懒汉模式:实例的创建在第一次使用对象时。

饿汉模式代码
static class Singleton{
        //期望singleton是一个单例类,只有一个实例
        //先创建一个成员,保存唯一的一个Singleton实例
        private static Singleton instance = new Singleton();
        //再提供一个方法,来获取到这个实例
        public static Singleton getInstance(){
            return instance;
        }
        //然后把类的构造方法设为private,防止其他代码再创建实例
        private Singleton(){

        }
    }

    public static void main(String[] args) {
        //只能通过getInstance方法来获取实例,
        //无法通过new的方法创建新的Singleton实例
        Singleton s = Singleton.getInstance();
    }
懒汉模式代码
//创建实例的时候是第一次使用getInstance方法的时候,比饿汉模式要迟
    static class Singleton{
        private static Singleton instance = null;
        public static Singleton getInstance(){
            if(instance == null){
                instance = new Singleton();
            }
            return instance;
        }
        private Singleton(){

        }
    }

    public static void main(String[] args) {
        Singleton s = Singleton.getInstance();
    }
线程安全问题

饿汉模式在类加载时已经创建好该单例对象,在获取单例对象时直接返回对象即可,不存在线程安全问题。
懒汉模式在使用对象时才实例化对象,所以存在线程安全问题。

如何保证懒汉模式的线程安全?
1.加锁
如果把synchronized加到getInstance方法外面,则相当于针对“判断、new、返回”三个操作进行加锁,这三个操作都是串行的,效率会更低;
如果把synchronized加到getInstance方法内部,则相当于针对“判断、new”两个操作进行加锁,效率相对会高一点,同时也保证了线程安全;如下图所示。
可以保证线程2的LOAD一定在线程1的SAVE后面;

代码如下:

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

此时线程的安全可以保证了,但效率会大大降低,因为每次调用getInstance方法都会涉及到加锁解锁,但实际上我们只有在instance未初始化时才涉及到线程安全问题,后面instance初始化之后只需要进行读操作即可,不会涉及到线程安全问题;所以只需要首次调用getInstance方法时加锁即可,后续就不用再调用了。所以需要引入双重if判定。

2.双重if判定

	if(instance == null){
        synchronized(Singleton.class){
            if(instance == null){
                instance = new Singleton();
            }
        }
	}

引入双重if判定就可保证加锁操作不再重复添加;

3.volatile
但是由于instance涉及到了读写操作,所以可能出现内存可见性的问题,即instance修改之后,线程2本应该从内存中读取不为空,但是可能是从寄存器中读取未被修改的instance,导致读出的数据为null,所以需要再添加一个volatile,保证外层if读取到的值是内存中的最新值。

	volatile private static Singleton instance = null;
总结

线程安全的单例模式,涉及的要点主要是3点:
1.加锁(在合适的位置加锁,保证把if和new都包裹起来,同时不要范围太大);
2.双重if(保证需要加锁的时候才加锁,一旦初始化完毕,就不必再加锁了);
3.volatile保证外层if读操作,读到的值都是内存中的最新的值。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/270614.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号