Java设计模式-多线程下的单例模式

  • 什么是单例模式?
    通过单例模式的方法创建的类在当前进程中只有一个实例
    通俗来说就是:在程序的运行中,一个类从始至终被调用了很多次,但是只被实例过一次

  • 单例模式-懒汉模式
    懒汉模式又称为饱汉模式,指的是在程序执行中需要用到该类的时候才去进行实例

        //懒汉模式
    	public class Singleton {
    	    private static Singleton singleton = null;
    		private Singleton() {
    		}
    		public static Singleton getInstance() {
    		 if (singleton == null) {
    			 //需要用到该类的时候才去进行实例
    		    singleton = new Singleton();
    		 }
    		 return singleton;
    		 }
    	}
    

    优点:使用时才实例化,懒加载启动快,资源占用小
    缺点:线程不安全-多个线程并发访问getInstance方法时singleton将被实例化多次

    针对于该缺点,有许多人直接给方法加上了synchronized关键字进行修饰,确实synchronized可以解决该线程不安全的缺点,然而又产生了另外一个缺点:性能低;因为synchronized为独占排他锁,当有多个线程同时访问getInstance方法时拿到执行权的只有一个线程,其他的线程则必须进行等待锁的释放。

    所以出现了解决的方案:双重加锁检查DCL

    	public class Singleton {
    
    	    //使用volatile修饰让变量每次在使用的时候,都从主存中取,而不是从各个线程的"工作内存"中取
    	    private volatile static Singleton instance = null;
    	    private Singleton(){	
    	    }
    	    public static Singleton getInstance(){
    			//判断是否已经实例过
    	        if(instance == null){
    				//同步块,线程安全的创建实例
    				synchronized(Singleton.class){
    				//再次检查实例是否存在,如果不存在才创建实例
    				 if(instance == null){
    						instance = new Singleton();
    	                }
    	            }
    	        }
    	        return instance;
    	    }
    	}
    

    为什么需要在同步块中再次检查实例是否存在呢?

    这个问题只需要明白如果去掉同步块中if会导致什么结果答案就呼之欲出了

    当多线程并发进入第一个if(instance == null)时,此时的instance还未进行实例,遇到了synchronized同步块,只有A线程进入了同步块中,其他的线程都在同步块外面等待锁的释放,A线程进入后对instance进行了实例,这个时候再次进入getInstance方法的其他线程都会直接获得实例化完成的instance,然而与A线程同时进入getInstance方法的其他的线程B、C还在等待A线程释放synchronized同步块的锁,当A线程释放锁后,B线程进入同步块后会再次实例instance,C线程同理,所以就导致了instance还是会被多次实例,这时就解释了为什么需要在同步块中再次检查实例是否存在Double Check。

  • 单例模式-饿汉模式
    在程序初始化(如tomcat启动)的时候就进行实例

    	public class Singleton {
    		private static Singleton instance = new Singleton();
    		private Singleton(){
    	    }
    	 	public static Singleton getInstance(){
    			return instance;
    		}
    	}
    

    优点:绝对的线程安全,第一次使用的时候也无需初始化没有延迟
    缺点:增加程序的启动时间,可能造成资源浪费(没用到该类)

  • 单例模式-内部类模式Holder(推荐)
    改成内部类,由JVM保证线程安全性

    	public class Singleton {
    		//类级的内部类,也就是静态的成员式内部类,该内部类的实例与外部类的实例
    	    private static class SingletonHolder{
    	        private static Singleton instance = new Singleton();
    	    }
    	    private Singleton(){
    	    }
    	    public static  Singleton getInstance(){
    	        return SingletonHolder.instance;
    	    }
    	}
    

    优点:将懒加载和线程安全完美结合的一种方式

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值