博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
单例模式讨论
阅读量:4220 次
发布时间:2019-05-26

本文共 3482 字,大约阅读时间需要 11 分钟。

在之前的博文中曾经介绍过单例模式:

https://blog.csdn.net/timchen525/article/details/78244101

这里重新讨论们下单例模式,并且引入了一个基于枚举的单例模式。

分析如下代码:
** * 懒汉模式 */public class SingletonExample {    // 私有构造函数    private SingletonExample() {    }    // 单例对象    private static SingletonExample instance = null;    // 静态的工厂方法    public static SingletonExample getInstance() {        if (null == instance) {            instance = new SingletonExample();        }        return instance;    }}

上述代码也叫作懒汉模式,即只在第一次被调用的时候才初始化,
不是线程安全的。不安全的原因:当两个线程同时运行到if(null == instance)则,同时进行instance = new SingleExample();即被实例化两次。
改进添加同步操作(synchronized):
public class SingletonExample {    // 私有构造函数    private SingletonExample() {    }    // 单例对象    private static SingletonExample instance = null;    // 静态的工厂方法    public static synchronized SingletonExample getInstance() {        if (null == instance) {            instance = new SingletonExample();        }        return instance;    }}
上述添加了synchronized使得该方法同一时刻只能被一个线程访问。因此,这种改进后的代码是线程安全的。
进一步基于synchronized进行改进:
public class SingletonExample {    // 私有构造函数    private SingletonExample() {    }    // 单例对象    private static SingletonExample instance = null;    // 静态的工厂方法    public static SingletonExample getInstance() {        if (null == instance) { // B            synchronized (SingletonExample.class) {                if (null == instance) { // 双重检测机制                    instance = new SingletonExample();  // A-3                }            }        }        return instance;    }}
分析:上述代码将同步synchronized移到判null之后,此时,可能有两个线程同时要去获取synchronized(SingletonExample.class),因此,在内部里面再次判断一次。这样写的好处,之后,null != instance可以直接return,而不用进行同步synchronized操作。
注意注意:上述
不是线程安全的。
instance = new SingletonExample()操作需要进行如下操作:
1)memory = allocate()分配对象的内存空间
2)ctorInstance()初始化对象
3)instance = memory设置instance的指向刚分配的内存
比如如下情况: JVM和CPU优化,发生了指令重排
1)memory = allocate()分配对象的内存空间
3)instance = memory设置instance的指向刚分配的内存
2)ctorInstance()初始化对象
比如:两个线程,线程B执行到if(instance == null) 此时,线程B执行到instance=new SingletonExample();而new的操作被CPU指令重拍,比如到
3),此时,instance == null判断不成立,变返回instance产生错误。
再次改进上述线程不安全的单例(添加volatile)(
线程安全写法,推荐
):
volatile + 双重检测机制 = 实现线程安全的单例模式
public class SingletonExample {    // 私有构造函数    private SingletonExample() {    }    // 单例对象    private volatile static SingletonExample instance = null;    // 静态的工厂方法    public static SingletonExample getInstance() {        if (null == instance) {            synchronized (SingletonExample.class) {                if (null == instance) {                    instance = new SingletonExample();                }            }        }        return instance;    }}
改进成
饿汉模式(线程安全的)
即单例模式在类加载时进行创建:
public class SingletonExample {    // 私有构造函数    private SingletonExample() {    }    // 单例对象    private static SingletonExample instance = new SingletonExample();    // 静态的工厂方法    public static SingletonExample getInstance() {        return instance;    }}
饿汉模式是
线程安全的,但是可能会引起程序初始化加载变慢,如果程序没有使用,则会造成资源浪费。
枚举模式实现线程安全(
最推荐,线程安全的
):
public class SingletonExample {    // 私有构造函数    private SingletonExample() {    }    public static SingletonExample getInstance() {        return Singleton.INSTANCE.getInstance();    }    private enum Singleton {        INSTANCE;        private SingletonExample singletonExample;        // JVM保证这个方法绝对只调用一次        Singleton() {            singletonExample = new SingletonExample();        }        public SingletonExample getInstance() {            return singletonExample;        }    }}
JVM保证构造函数Single()被调用一次,因此是线程安全的。
你可能感兴趣的文章
C语言文件操作详解
查看>>
C语言详解 FILE文件操作
查看>>
磁盘I/O那些事
查看>>
Linux下的IO监控与分析
查看>>
ZeroMQ
查看>>
ZeroMQ编译安装使用教程
查看>>
Linux配置ntp时间服务器(全)
查看>>
Linux Wireless架构总结
查看>>
带宽与延时知识整理
查看>>
无线电信号怎么传输的
查看>>
wifi提速技巧:十大方法瞬间提升wifi速度
查看>>
WIFI 的 传输信道 与标准 WIFI的频道 传输能力
查看>>
CAN网络学习总结
查看>>
Linux CAN说明文档
查看>>
freescale IMX6Q git 获取源码
查看>>
Freesclae i.MX6 Linux PCIE驱动源码分析
查看>>
(一)Yocto的介绍
查看>>
卡尔曼滤波,最最容易理解的讲解.找遍网上就这篇看懂了
查看>>
SLAM的前世今生 终于有人说清楚了
查看>>
激光定位原理的理解
查看>>