【单例深思】懒汉式改进版与内置锁
来源:互联网 发布:分辨率300的软件 编辑:程序博客网 时间:2024/06/06 17:01
我们知道懒汉式的实现是延迟加载(Lazy Loading),但是不是线程安全的,下面我们深入研究下为什么。
懒汉式的实现如下:
public class Singleton {
private static Singleton singleton;
private Singleton(){}
public static Singleton getInstance() {
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
}相比于饿汉式实现,懒汉式是线程安全的,因为懒汉式中的类成员singleton在声明时没有立即使用new 关键字实例化,而是在getInstance()方法里面才使用new 进行实例化,此时Singleton类的初始化不会实例化singleton。
只有当外部调用使用静态的getInstance()方法时,类成员singleton才会被分配内存实例化,因此就达到了延迟加载的目的。
如有疑问,可参照【单例深思】饿汉式与类加载
接下来我们重点来看看懒汉式为什么不是线程安全的?
在多线程情况下,如果singleton还没有被实例化,此时它的值为null,如果这时有可能多个线程同时进入getInstance()方法中,同时执行 if (singleton == null)这行代码,得到的结果都为true,于是这些线程都会使用new Singleton();为singleton分配内存,这时singleton 就不是单例了,所以懒汉式就不是线程安全的。
懒汉式改进版解决了这个问题,其实现如下:
public class Singleton {
private static Singleton instance;
private Singleton(){}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}其只改进了一个地方,就是使用关键字synchronized 来声明getInstance()方法。这个关键字的作用就是给getInstance()加锁,加锁后这个方法就具备了原子性,每次只能由一个线程执行这个方法,其他请求线程则会被阻塞,直到活跃线程执行完毕。如果每次只有一个线程执行这个方法中的代码,那么我们上面讨论的线程安全问题就不复存在了,不会出现创建多个实例的情况了。
Java 提供了一种内置的锁机制来支持原子性(一组语句作为一个不可分割的单元被执行):同步代码块(Synchronized Block),同步代码块包括两部分,一个作为锁的对象引用,一个作为由这个锁保护的代码块。以关键字synchronized 来修饰的方法就是一种横跨整个方法体的同步代码块,其中该同步代码块的锁就是方法调用所在的对象。静态的synchronized 方法以Class 对象作为锁。
synchronized(lock){
//由锁保护的代码块
} 每个Java对象都可以用做一个实现同步的锁,这些所被称为内置锁。
线程进入同步代码块之前会自动获得锁,并且在退出同步代码块时自动释放锁,而无论是通过正常的控制路径退出,还是通过从代码块中抛出异常退出。获得内置锁的唯一途径就是进入由这个锁保护的同步代码块或方法。
Java 的内置锁相当于一个互斥体(或互斥锁),这意味着最多只有一个线程能持有这种锁,当线程A尝试获取一个由线程B持有的锁时,线程A必须等待或阻塞,直到线程B释放这个锁。如果线程B永不释放这个锁,那么A就永远等待下去。
懒汉式改进版中getInstance()方法是静态的synchronized 方法,因此以Singleton.Class 作为锁,线程只有获得了这个锁才能执行getInstance()方法,因此保证了线程安全性。但是这个锁只有一个,意味着同一时刻只能有一个线程执行该方法。如果这个单例很火,有很多线程需要获取它,那么就会影响单例的获取。这也是synchronized 方法的一个弊端,代码的性能比较糟糕。这种简单且粗粒度的方法能确保线程安全性,但是不能同时处理多个请求,付出的代价很高。
这也就是双重检测锁实现出现的原因,通过缩小锁的粒度来增强活跃度,这将在下篇文章中详细讨论。
1 0
- 【单例深思】懒汉式改进版与内置锁
- 单例模式 饿汉式与懒汉式
- 单例懒汉式
- 【单例深思】双重检测锁与Java内存模型
- 【单例深思】饿汉式与类加载
- 单例模式---懒汉式
- 单例模式-懒汉式
- 单例之懒汉式
- 单例模式 懒汉式与恶汉式
- 单例模式 懒汉式与恶汉式
- 单例模式(饿汉式与懒汉式)
- 设计模式:单例中的 饿汉式 与懒汉式
- java 单例模式:饿汉式与懒汉式
- java 单例模式:饿汉式与懒汉式 区别
- 单例模式分类之懒汉式与饿汉式
- 单例模式中的饿汉式与懒汉式
- java 单例模式:饿汉式与懒汉式
- 单例模式分类之懒汉式与饿汉式
- 《Context Aware Query Image Representation for Particular Object Retrieval》论文阅读
- 1005. 继续(3n+1)猜想 (25)
- Bootstrap 知识点
- Spring MVC学习(四)-------Controller接口控制器详解7(完)
- 静态方法不能调用非静态方法的原因
- 【单例深思】懒汉式改进版与内置锁
- 每天一个Linux命令(9):touch
- MWC(1) Multiwii 飞控程序初学者概要
- Spring MVC学习(五)-------处理器拦截器详解
- mysql view 更新问题
- P1006 传纸条
- 蓝桥杯省赛12
- 最大连续子序列求和详解
- 利用VS2013在win7 64位机器上搭建xgboost 0.6+Anaconda3 环境