单例模式和双重检测的小结

设计模式的经典模式之一——单例模式

这个也是面试经常被问起的面试,一般都要求手写

【饿汉模式】非延时加载 ——以空间换时间

懒汉模式】延时加载——以时间换空间

看似简单,但是在懒汉模式还隐藏了一个双重检测,其中还是涉及到JVM内存的“无序写入”问题(后面使用的 volatile )

1、饿汉模式

比较简单,非延时加载,一上来就把对象给new出来了

<span style="font-family:Microsoft YaHei;font-size:14px;">public class Singleton {
	private Singleton(){} //默认构造器
	private static Singleton instance = new Singleton();//直接加载
	public Singleton getIntance(){
		return instance;
	}
}</span>

2、懒汉模式,延时加载

【1】普通

<span style="font-family:Microsoft YaHei;font-size:14px;">public class Singleton {
	private Singleton() { } // 默认构造器

	private static Singleton instance = null;// 延时加载
	//每次运行都要创建实例因而需要加锁保护
	public static synchronized Singleton getIntance() {
		if (instance == null) {
			instance = new Singleton();// 判断之后加载
		}
		return instance;
	}

}</span>

【2】双重检测(有缺陷来自JVM自身)

上面尽管这样做到了线程安全,并且解决了多实例问题,但并不高效。在任何调用这个方法的时候,你都需要承受同步带来的性能开销,然而同步只在第一次调用的时候才被需要,也就是单例类实例创建的时候。这将促使我们使用双重检查锁模式(double checked locking pattern),一种只在临界区代码加锁的方法。一般称其为双重检查锁,因为会有两次检查 _instance == null,一次不加锁,另一次在同步块上加锁。

<span style="font-family:Microsoft YaHei;font-size:14px;">public class Singleton {
	private Singleton() { } // 默认构造器

	private volatile static Singleton instance = null;// volatile 可见性/防止重排序

	public static Singleton getIntance() {
		// 第一重判断
		if (instance == null) {
			// 锁定代码块
			synchronized (Singleton.class) {
				// 第二重判断
				if (instance == null) {
					instance = new Singleton();// 判断之后加载
				}

			}

		}
		return instance;
	}

}</span>

如果使用双重检查锁定来实现懒汉式单例类,需要在静态成员变量instance之前增加修饰符volatile(可见性,防止重排序),被volatile修饰的成员变量可以确保多个线程都能够正确处理,且该代码只能在JDK 1.5及以上版本中才能正确执行。

【3】ThreadLocal模式的单例

<span style="font-family:Microsoft YaHei;font-size:14px;">    public class Singleton{  
      public static final ThreadLocal  threadInstance=new ThreadLocal();  
     public static Singleton singleton=null;  
      public static getSingleton(){  
         if(threadInstance.get()==null){  
             createSingleton();  
          }  
      }  
      public static Singleton createSingleton(){  
         synchronized(Singleton.class){  
           if(singleton==null){  
                singleton=new Singleton();  
            }  
          }  
      }  
      
    }   </span>


ThreadLocal的全局变量局部化 第一次检测采用线程局部来做如果线程已经访问过则不需要进入同步块

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值