美文网首页
单例模式(懒汉模式)

单例模式(懒汉模式)

作者: dependmyse | 来源:发表于2016-08-23 17:39 被阅读0次
    package com.exam.test;
    
    /**
     * 懒汉式单例
     * Created by xiangyang.laixiang on 2016/8/23.
     */
    public class SingleInstance {
        private static SingleInstance singleInstance;
    
        /**
         * 懒汉式单例,非线程安全
         * @return
         */
        public static SingleInstance getSingleInstance(){
            if(singleInstance == null)
            {
                singleInstance = new  SingleInstance();
            }
            return singleInstance;
        }
    
        /**
         * 懒汉式单例,线程安全
         * 这是实现线程安全最简单的方式,但这里会导致一个性能问题,因为我们把整个getInstance同步起来了,
         * 这就会导致每时每刻都只能有一个线程调用getInstance方法,而同步只发生在第一次声明的时候
         * 这就引出了双重检验锁的概念
         * @return
         */
        public synchronized static SingleInstance getSingleInstance2(){
            if(singleInstance == null)
            {
                singleInstance = new  SingleInstance();
            }
            return singleInstance;
        }
    }
    
    
    /**
     * 双重检验锁
     */
    class DoubleCheckSingleInstance{
        //使用volatile关键字修饰
        //private static DoubleCheckSingleInstance singleInstance;
        private static DoubleCheckSingleInstance singleInstance;
        public static DoubleCheckSingleInstance getSingleInstance()
        {
            if(singleInstance == null)
            {
                synchronized (DoubleCheckSingleInstance.class)
                {
                    if(singleInstance == null)
                    {
                        singleInstance = new DoubleCheckSingleInstance();
                    }
                }
            }
            return singleInstance;
        }
    
        /**
         * 上述这段代码看起来很完美,但是中间存在着一个问题那就是 new DoubleCheckSingleInstance()
         * 这个操作不是原子操作,大致有三步构成。
         * 1. 给instance分配内存
         * 2. 调用DoubleCheckSingleInstance构造函数初始化成员变量
         * 3. 将instance指向内存
         * 问题就出在这一部分,jvm即时编译器中存在着指令重排序的优化。如果1,2,3的执行步骤不会存在问题
         * 倘若1,3,2
         * 那么当线程二执行完第三步以后,线程三抢占cpu资源,则进行检查,发现instance不为空,则返回,但此时
         * 成员变量尚未初始化,则会发生调用错误。
         * 解决方案是使用volatile来修饰singleInstance来强制每次都从内存映像中读取数据,其实volitile也可以起到
         * 禁止重排序的功能,在java1.5以后使用比较安全。(1.5之前的内存模型是存在问题的)
         */
    }
    
    /**
     * effective java中推荐的内部类实现单例的写法 。
     */
    class SingtonInstance{
        private SingtonInstance()
        {
            System.out.println("constructor");
        }
        private static class SingtonHolder{
            private static SingtonInstance instance = new SingtonInstance();
        }
        public static void beforeInvoke()
        {
            System.out.println("before invoke");
        }
    
        public static SingtonInstance getInstance()
        {
            /**
             * 此处最开始理解有点绕,但是经过我对象的一个提醒恍然明白,对于内部类的所有对象对于其
             * 外部类来说都是可见的,简直是霸气,否则private的可见范围是不允许直接访问的。
             */
            return SingtonHolder.instance;
        }
    }
    
    public class Test {
        public static void main(String[] args) {
            SingtonInstance.beforeInvoke();
            SingtonInstance.getInstance().beforeInvoke();
        }
    }
    
    

    相关文章

      网友评论

          本文标题:单例模式(懒汉模式)

          本文链接:https://www.haomeiwen.com/subject/adrnsttx.html