多线程学习笔记二 - 多线程与单例模式

单例设计模式与多线程:
  设计模式:对问题行之有效的解决方式。其实是一种思想。
  单例设计模式:
    解决的问题:可以保证一个类在内存中的对象唯一性。
    比如对于多个程序使用同一个配置信息对象时,都需要保证对象的唯一性。
  如果保证唯一性?
    1.不允许其他程序用new创建该类对象。
    2.在该类中创建一个本类实例。
    3.对外提供一个方法,让其他程序可以获取对象。
  实现步骤:
    1.私有化该类的构造函数。
    2.通过new在本类中创建一个本类对象。
    3.定义一个共有的方法,将创建的对象返回。

class Single{
        private Single(){}
        
        Single s = new Single();
        
        public void getInstance(){
            return s;
        }
    }    

    接下来我们要如何调用这个对象呢?通过私有化Single类的构造函数,已经组织了我们new该类,那么就要通过类名.getInstance();的形式获得该类的对象。
    所以该方法必须是静态的,因为该方法要返回s,所以s也要是静态的。

class Single{
        private Single(){}
        
        static Single s = new Single();
        
        public static void getInstance(){
            return s;
        }
    }

    因为s为成员变量,所以我们可以通过类名.s的形式即Single.s的方法获得该类的对象,为什么还有弄一个方法呢?
    通过方法的访问可以实现可控性。例如我可以在方法中传一个参数,只要传入的参数满足某个条件才返回s,这叫可控性。
    s为Single类的成员变量,我们一般不会吧成员变量暴露出去,原因就是为了可控。

class Single{
        private Single(){}
        
        private static Single s = new Single();
        
        public static void getInstance(){
            return s;
        }
    }

    以上为单例模式的基本思想。只要在任何一个类中加入以上代码,就能保证该类对象的唯一性。
    这种方法类一加载就创建对象。下面介绍另外一种:

class Single{
        private Single(){}
        
        private static Single s = null;
        
        public static void getInstance(){
            if(s == null){
                s = new Single();
                return s;
            }
        }
    }

    以上这种形式是当调用方法时才创建对象。也称为延迟加载形式。
    为了区分两种形式:第一种叫做饿汉式,第二种叫做懒汉式。开发用饿汉式,面试用懒汉式,因为懒汉式包含的知识点比较多。
    懒汉式在多线程中会有安全隐患问题。
    为什么饿汉式没有呢?
    多线程的安全问题发生的原因除了有多个线程共同访问一个共享资源外,还有一个原因就是执行操作共享数据的代码有多条。
    而饿汉式只有一条-->return s;所以不会发生安全问题。
解决饿汉式:

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

    但是上述解决方法每次调用该方法的时候都会判断锁,降低了效率。为了提高效率我们对该代码进行改写,不用同步函数锁,改用同步块锁。

class Single{
        private Single(){}
        
        private static Single s = null;
        
        public static void getInstance(){
            if(s == null){
                synchronized(Single.class){//注意:此方法为静态方法不能用this;
                    if(s == null){
                        s = new Single();
                        return s;
                    }
                }
            }
        }
    }

    解释:使用同步块锁是为了解决线程安全问题,多加一次判断是为了提高效率。
    综上所述:开发还是用饿汉式好。

posted @ 2015-07-28 23:30  宫商角徵羽  阅读(197)  评论(0编辑  收藏  举报