我用 Dcl写出了单例模式
大多数初学者在接触到这种写法的时候已经感觉是「高大上」了,首先是判断实例对象是否为空,如果为空那么就将该对象的 Class 作为锁,这样保证同一时刻只能有一个线程进行访问,然后再次判断实例对象是否为空,最后才会真正的去初始化创建该实例对象。一切看起来似乎已经没有破绽,但是当你学过JVM后你可能就会一眼看出猫腻了。没错,问题就在 instance = new SingleTonDcl(); 因为这不是一个原子的操作,这句话的执行是在 JVM 层面分以下三步: 1.给 SingleTonDcl 分配内存空间 2.初始化 SingleTonDcl 实例 3.将 instance 对象指向分配的内存空间( instance 为 null 了) 正常情况下上面三步是顺序执行的,但是实际上JVM可能会「自作多情」得将我们的代码进行优化,可能执行的顺序是1、3、2,如下代码所示设现在有两个线程 t1, t2
该怎么解决呢,既然问题出在指令有可能重排序上,不让它重排序不就行了,volatile 不就是干这事的吗,我们可以在 instance 变量前面加上一个 volatile 修饰符内部类的特点: 这种写法使用 JVM 类加载机制保证了线程安全问题;由于 SingleTonStaticInnerClass 是私有的,除了 getInstance() 之外没有办法访问它,因此它是懒汉式的;同时读取实例的时候不会进行同步,没有性能缺陷;也不依赖 JDK 版本; 但是,它依旧不是完美的。 不安全的单例 上面实现单例都不是完美的,主要有两个原因 1. 反射攻击 首先要提到 java 中让人又爱又恨的反射机制, 闲言少叙,我们直接边上代码边说明,这里就以 DCL 举例(为什么选择 DCL 因为很多人觉得 DCL 写法是最高大上的....这里就开始去”打他们的脸“)
将上面的 DCl 的测试代码修改如下: (编辑:江门站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |