• [二]多线程编程-单例模式


    继 多线程编程-实现及锁机制:http://www.cnblogs.com/wangfajun/p/6547648.html,我们开始第二篇文章啦。。。

    穿插一个小的知识点。单例模式,因为这个模式要学会了线程同步,才比较好讲这个知识点。

    (好像刚出来的那会,面试中基本会问这个问题,或者笔试中让你写一个单利模式,有记忆吧。哈哈。。。青春一去不复返啊。。)

    1饱汉模式:

    class Single{
        public static final Single single = new Single();
        public static Single getInstance(){
            return single;
        }
    }

    初始化时,就给你创建了一个实例化对象,不会出现线程安全问题,再看看懒汉模式:

    2..懒汉模式(延迟加载):

    class Single{
        public static Single single = null;
        public static Single getInstance(){
            if(single == null){
                single = new Single();
            }
            return single;
        }
    }

    假如现在有A、B两个线程,同时访问getInstance方法时,分析下执行过程:

    1.A线程进入if条件判断,发现single为null,然后线程A挂在这了,

    2.B线程进来了,然后也挂这了,

    3.A线程活了,继续往下执行,new了一个Single对象出来了

    4.B线程也活了,往下执行又创建了一个Single对象

    这样是不是线程又不安全了?没错。。。。听明白了否?

    如何解决?修改代码如下:

    class Single{
        public static Single single = null;
        public static synchronized Single getInstance(){
            if(single == null){
                single = new Single();
            }
            return single;
        }
    }

    加了一个 synchronized 来修饰,每个线程想要获得这个Single实例的时候,都要判断锁,我们发现,线程安全了。。。

    不过虽然这样解决了线程安全问题,但是getInstance()方法效率比较低,如何提高效率?接着修改代码:

    class Single{
        public volatile static Single single = null;
        public static Single getInstance(){
            if(single==null){
                synchronized(Single.class){
                    if(single == null){
                        single = new Single();
                    }
                }
            }
            return single;
        }
    }

    将同步函数变成同步代码块,然后再在同步代码块外包了一层if条件判断,为什么这么做就提升了效率?假设现在有A、B.等等多个线程,再来分析下执行过程:

    1.A线程进入synchronized方法块中,获得了锁,挂这了

    2.B线程进入最外层if条件判断,single为null,满足,继续执行,发现锁被A线程拿着了,进不去,B线程挂这了

    3.A线程活了,进入内层if条件判断,single为null,满足,new了一个Single对象出来,释放了锁,此时single已经被实例化了

    4.B线程活了,进入了synchronized方法块种,内层if条件判断,不满足,执行return single.

    后续的其他线程进来,判断最外层if条件判断,single都不为空了,直接返回,这样效率是不是提升了?

    还有一种方式:静态内部类

    public class InnerClass {
    	private static class Single{
    		private static Single single = new Single();
    	}
    	private static Single getInstance(){
    		return Single.single;
    	}
    }
    

    了解以上这些,我来问几个问题:

    1.懒汉式有什么特点?

      延迟加载

    2.懒汉模式有没有问题?

      当多线程访问的时候,会出现线程安全问题

    3.如何解决?

      加同步函数或者同步代码块,不过会出现效率问题,可以加双重判断的方式来解决。

    4.加同步的时候,使用的锁是哪一个?

      该类所属的字节码所属对象

     介绍了上面两种模式,接下来再介绍一种单例模式(枚举)

    public class Single {
        
        //不允许外部创建实例
        private Single(){}
        
        public static Single getInstance(){
            return SingleEnum.INSTANCE.getInstance();
        }
        
        private enum SingleEnum{
            INSTANCE;
            
            private Single single = null;
            
            SingleEnum(){
                single = new Single();
            }
            
            public Single getInstance(){
                return single;
            }
        }
        
    }

    这种模式相对于懒汉模式更加快速安全,相对于饱汉模式,更加节省资源。

    构造函数SingleEnum永远只会被调用一次。

  • 相关阅读:
    Java中NIO和IO区别和适用场景
    JDK和CGLIB动态代理原理
    java中的Serializable接口的作用
    redis采用序列化方案存对象
    在时间复杂度为O(n)且空间复杂度为O(1)的情况下翻转链表
    给定一个排好序的数组,然后求出丢失的数字
    求字符串里超过字符长度一半的元素
    求你给定两字符串包含的字母数是否完全一致
    动态规划,求数组不相邻数字的最大子串值
    JWT 工具
  • 原文地址:https://www.cnblogs.com/wangfajun/p/6549870.html
Copyright © 2020-2023  润新知