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

继 多线程编程-实现及锁机制: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永远只会被调用一次。

原文地址:https://www.cnblogs.com/wangfajun/p/6549870.html