java单例模式具体解释_Java的几种单例模式及特点

1、Java常见的单例模式(懒汉、饿汉、双重锁模式)

1.1饿汉模式

public class Singleton_e {

private static final Singleton_e instance = new Singleton_e();

private Singleton_e() {

System.out.println("这是单例模式之:饿汉模式");

}

public static Singleton_e getInstance() {

return instance;

}

}

从时间和空间方面分析: 饿汉式是典型的空间换时间,当类装载的时候就会创建类实例,不管你用不用,先创建出来,然后每次调用的时候,就不需要再判断了,节省了运行时间。

从线程安全方面分析:饿汉式是线程安全的,因为虚拟机保证只会装载一次,在装载类的时候是不会发生并发的。

1.2懒汉模式

public class Singleton_lan {

private static Singleton_lan instance = null;

private Singleton_lan() {

System.err.println("这是单例模式之:懒汉模式");

}

public static synchronized Singleton_lan getInstance() {

if (instance == null) {

instance = new Singleton_lan();

}

return instance;

}

}

从时间和空间方面分析: 懒汉式是典型的时间换空间,也就是每次获取实例都会进行判断,看是否需要创建实例,浪费判断的时间。当然,如果一直没有人使用的话,那就不会创建实例,则节约内存空间。

从线程安全方面分析:懒汉式从线程安全性上讲,不加同步的懒汉式是线程不安全的,比如,有两个线程,一个是线程A,一个是线程B,它们同时调用getInstance方法,那就可能导致并发问题

1.3双重检查锁模式(DCL)

public class Singleton_shuangchongsuo {

private static Singleton_shuangchongsuo instance = null;

private Singleton_shuangchongsuo() {

System.out.println("这是单例模式之:双重锁模式");//(1)

}

public static Singleton_shuangchongsuo getInstance() {

if (instance == null) {//(2)

synchronized (instance) {//(3)

if (instance == null) {//(4)

instance = new Singleton_shuangchongsuo();//(5)

}

}

}

return instance;//(6)

}

}

双重锁模式简称DCL(double check lock)相当于对懒汉模式进行了增强,保证多线程访问时安全问题(但是不符合happens-before原则,后面会讨论)。

当然如果直接在Singleton_shuangchongsuo()方法上加锁也可以达到目的,但是这样的话,每次获取实例都要去判断一下是否加锁,造成效率低下。而双重锁只会在特殊情况(第一次创建实例instance时,可能会产生多个实例同时访问的情况下)才会判断锁是哪个,相对效率高。

1.4、用happens-before规则重新审视双重检查锁模式(DCL)

我想简单的用对象创建期间的实际场景来分析一下:(以下是我的个人的理解,所看的资料也是非官方的,不完全保证正确。)

还是看上面1.3双重锁模式的代码,假设线程1执行完(5)时,线程2正好执行到了(2);

看看 new Singleton_shuangchongsuo(); 这个语句的执行过程: 它不是一个原子操作,实际是由多个步骤,我们从我们关注的角度简化一下,简单的认为它主要有2步操作好了:

a) 在内存中分配空间,并将引用指向该内存空间。

b) 执行对象的初始化的逻辑(和操作),完成对象的构建。

此时因为线程1和线程2没有用同步,他们之间不存在“Happens-Before”规则的约束,所以在线程1创建Singleton_shuangchongsuo对象的 a),b)这两个步骤对于线程2来说会有可能出现a)可见,b)不可见

造成了线程2获取到了一个未创建完整的Singleton_shuangchongsuo对象引用,为后边埋下隐患。

改进后的DCL代码:

public class Singleton_lan2 {

private Singleton_lan2(){

System.out.println("这是对饿懒模式的的增强,解决由双重锁模式代码未遵循happens-before原则带来的问题");

}

private static class InstanceHolder {//1 static

private static final Singleton_lan2 instance = new Singleton_lan2();//2 static

}

public static Singleton_lan2 getInstance(){//3 该static保证不需要实例化Singleton_lan2调用该静态方法

return InstanceHolder.instance;//通过1、2的static关键字保证可以访问静态类中的静态变量

}

}

以上代码是通过静态内部类的方式实现。当getInstance方法第一次被调用的时候,它第一次读取InstanceHolder.instance,导致InstanceHolder类得到初始化;而这个类在装载并被初始化的时候,会初始化它的静态域,从而创建Singleton的实例,由于是静态的域,因此只会在虚拟机装载类的时候初始化一次,并由虚拟机来保证它的线程安全性。这个模式的优势在于,getInstance方法并没有被同步,并且只是执行一个域的访问,因此延迟初始化并没有增加任何访问成本。

更多相关DCL的修正请参考以下文章:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值