Java创建线程安全的单例singleton

Java创建线程安全的单例singleton

Java创建线程安全的单例

单例的使用场景

  • JVM中仅需要一个实例,因此能节省内存,加快访问速度,比如数据库连接池,计数器等。
  • Spring 中的Bean,默认也是单例的,
  • 共享资源的访问,比如日志文件,系统配置

单例的实现

要实现一个单例,首先要把构造方法设置成私有的,并且要提供一个返回实例的方法

1、实现一个单例,单线程是安全的,多线程中不安全,代码如下:

Java创建线程安全的单例singleton

单线程安全的单例模式

如果多线程下,如果第一个线程执行检查instance是否为null,如果为null,执行创建一个Singleton1的实例,在实例未被初始化完毕的时候,第二个线程检查instance是否为null,这时候是null,也会创建一个实例。这时候就会有两个实例。

2、多线程下的安全单例,第一种方式就是方法加锁来实现,比如添加关键字synchronized。

Java创建线程安全的单例singleton

多线程下的安全单例

添加了一个synchronized关键字,实现了多线程下的安全单例,每次获取会锁住Class对象,导致性能不高。

3、多线程下的安全单例,第二种方式就是双重检查,下面的实现方式有问题吗?

Java创建线程安全的单例singleton

实现双重检查

不在方法上添加synchronized,在instance为null的时候才会添加锁,这样效率提高了不少,但是在多线程下面可能会出现问题。原因是创建实例的时候,有几个步骤(分配空间,初始化,把instance执行分配的地址),这几个步骤会被处理器重排序,导致在没有完全初始化的情况下其他线程获取了实例,可能会导致莫名其妙的问题。

4、第三种方式实现多线程下的安全单例,在上个例子中,把instance设置为volatile,这个关键字能保可见性,其实是阻止了重排序(分配空间,初始化,把instance执行分配的地址)。

Java创建线程安全的单例singleton

第三种方式实现多线程下的安全单例

5、第四种方式实现多线程下的安全单例,使用饿汉式,缺点就是不能延迟加载。

Java创建线程安全的单例singleton

饿汉式多线程下的安全单例

6、第五种方式实现多线程下的安全单例,基于类的初始化,在类初始化的时候,JVM会获取一个锁,这个锁可以同步多个线程对同一个类的初始化。

Java创建线程安全的单例singleton

基于类的初始化的单例


分享到:


相關文章: