首页编程java编程java中什么是双重锁?什么是双重检查锁定,为什么要进行双重检查锁定

java中什么是双重锁?什么是双重检查锁定,为什么要进行双重检查锁定

编程之家2023-10-14117次浏览

大家好,关于java中什么是双重锁很多朋友都还不太明白,不过没关系,因为今天小编就来为大家分享关于什么是双重检查锁定,为什么要进行双重检查锁定的知识点,相信应该可以解决大家的一些困惑和问题,如果碰巧可以解决您的问题,还望关注下本站哦,希望对各位有所帮助!

java中什么是双重锁?什么是双重检查锁定,为什么要进行双重检查锁定

java中的DCL是什么意思

简单的Java对象(Plain Ordinary Java Objects)实际就是普通JavaBeans,使用POJO名称是为了避免和EJB混淆起来,而且简称比较直接.其中有一些属性及其getter setter方法的类,有时可以作为value object或dto(Data Transform Object)来使用.当然,如果你有一个简单的运算属性也是可以的,但不允许有业务方法,也不能携带有connection之类的方法。 POJO是Plain Ordinary Java Objects的缩写不错,但是它通指没有使用Entity Beans的普通java对象,可以把POJO作为支持业务逻辑的协助类。 POJO有一些private的参数作为对象的属性。然后针对每个参数定义了get和set方法作为访问的接口。例如: public class User{ private long id; private String name; public void setId(long id){ this.id= id;}public void setName(String name){ this.name=name;}public long getId(){

什么是双重检查锁定,为什么要进行双重检查锁定

单例类在Java开发者中非常常用,但是它给初级开发者们造成了很多挑战。他们所面对的其中一个关键挑战是,怎样确保单例类的行为是单例?也就是说,无论任何原因,如何防止单例类有多个实例。在整个应用生命周期中,要保证只有一个单例类的实例被创建,双重检查锁(Double checked locking of Singleton)是一种实现方法。顾名思义,在双重检查锁中,代码会检查两次单例类是否有已存在的实例,一次加锁一次不加锁,一次确保不会有多个实例被创建。顺便提一下,在JDK1.5中,Java修复了其内存模型的问题。在JDK1.5之前,这种方法会有问题。本文中,我们将会看到怎样用Java实现双重检查锁的单例类,为什么Java 5之前的版本双重检查锁会有问题,以及怎么解决这个问题。顺便说一下,这也是重要的面试要点,我曾经在金融业和服务业的公司面试被要求手写双重检查锁实现单例模式、相信我,这很棘手,除非你清楚理解了你在做什么。你也可以阅读我的完整列表“单例模式设计问题”来更好的准备面试。

为什么你需要双重检查锁来实现单例类?

java中什么是双重锁?什么是双重检查锁定,为什么要进行双重检查锁定

一个常见情景,单例类在多线程环境中违反契约。如果你要一个新手写出单例模式,可能会得到下面的代码:

private static Singleton _instance;

public static Singleton getInstance(){

java中什么是双重锁?什么是双重检查锁定,为什么要进行双重检查锁定

if(_instance== null){

_instance= new Singleton();

}

return _instance;

}

然后,当你指出这段代码在超过一个线程并行被调用的时候会创建多个实例的问题时,他很可能会把整个getInstance()方法设为同步(synchronized),就像我们展示的第二段示例代码getInstanceTS()方法一样。尽管这样做到了线程安全,并且解决了多实例问题,但并不高效。在任何调用这个方法的时候,你都需要承受同步带来的性能开销,然而同步只在第一次调用的时候才被需要,也就是单例类实例创建的时候。这将促使我们使用双重检查锁模式(double checked locking pattern),一种只在临界区代码加锁的方法。程序员称其为双重检查锁,因为会有两次检查 _instance== null,一次不加锁,另一次在同步块上加锁。这就是使用Java双重检查锁的示例:

public static Singleton getInstanceDC(){

if(_instance== null){// Single Checked

synchronized(Singleton.class){

if(_instance== null){// Double checked

_instance= new Singleton();

}

}

}

return _instance;

}

这个方法表面上看起来很完美,你只需要付出一次同步块的开销,但它依然有问题。除非你声明_instance变量时使用了volatile关键字。没有volatile修饰符,可能出现Java中的另一个线程看到个初始化了一半的_instance的情况,但使用了volatile变量后,就能保证先行发生关系(happens-before relationship)。对于volatile变量_instance,所有的写(write)都将先行发生于读(read),在Java 5之前不是这样,所以在这之前使用双重检查锁有问题。现在,有了先行发生的保障(happens-before guarantee),你可以安全地假设其会工作良好。另外,这不是创建线程安全的单例模式的最好方法,你可以使用枚举实现单例模式,这种方法在实例创建时提供了内置的线程安全。另一种方法是使用静态持有者模式(static holder pattern)。

/*

* A journey to write double checked locking of Singleton class in Java.

*/

class Singleton{

private volatile static Singleton _instance;

private Singleton(){

// preventing Singleton object instantiation from outside

}

/*

* 1st version: creates multiple instance if two thread access

* this method simultaneously

*/

public static Singleton getInstance(){

if(_instance== null){

_instance= new Singleton();

}

return _instance;

}

/*

* 2nd version: this definitely thread-safe and only

* creates one instance of Singleton on concurrent environment

* but unnecessarily expensive due to cost of synchronization

* at every call.

*/

public static synchronized Singleton getInstanceTS(){

if(_instance== null){

_instance= new Singleton();

}

return _instance;

}

/*

* 3rd version: An implementation of double checked locking of Singleton.

* Intention is to minimize cost of synchronization and improve performance,

* by only locking critical section of code, the code which creates instance of Singleton class.

* By the way this is still broken, if we don't make _instance volatile, as another thread can

* see a half initialized instance of Singleton.

*/

public static Singleton getInstanceDC(){

if(_instance== null){

synchronized(Singleton.class){

if(_instance== null){

_instance= new Singleton();

}

}

}

return _instance;

}

}

这就是本文的所有内容了。这是个用Java创建线程安全单例模式的有争议的方法,使用枚举实现单例类更简单有效。我并不建议你像这样实现单例模式,因为用Java有许多更好的方式。但是,这个问题有历史意义,也教授了并发是如何引入一些微妙错误的。正如之前所说,这是面试中非常重要的一点。在去参加任何Java面试之前,要练习手写双重检查锁实现单例类。这将增强你发现Java程序员们所犯编码错误的洞察力。另外,在现在的测试驱动开发中,单例模式由于难以被模拟其行为而被视为反模式(anti pattern),所以如果你是测试驱动开发的开发者,最好避免使用单例模式。

java单例双重检查锁为什么需要加volatile关键字

已经修改,的确应该加上volatile关键字。不加的情况下,假设两个线程,线程A正在执行instance= new Instance()的操作,而线程B开始执行if(instance==null)的判断,当不存在volatile的时候,因为 new Instance()是一个非原子操作,可能发生无序写入,构造函数可能在整个对象构造完成前执行完毕,线程B可能会看到一个不完整的instance对象,因为java的某些实现会在内存中开辟一片存储对象的区域后直接返回内存的引用,所以线程B判断不为null,而这时候实际上,instance的构造函数还没有执行,从而线程b得到不完整的对象。在 Instance的构造函数执行之前,会在内存中开辟一片存储对象的区域后直接返回内存的引用,赋值给变量 instance,instance也就可能成为非 null的,即赋值语句在对象实例化之前调用,此时别的线程得到的是一个还会初始化的对象,这样会导致系统崩溃线程B可能会看到一个不完整的instance对象,因为java的某些实现,所以线程B判断不为null。从而得到不完整的对象。

OK,本文到此结束,希望对大家有所帮助。

java用什么代替了指针 Java语言没有指针,怎样实现链表lt lt 是什么意思java?lT是什么意思