【Java】设计模式【1.3】-- 为什么饿汉式单例是线程安全的?

我们都知道,饿汉式单例是线程安全的,也就是不会初始化的时候创建出两个对象来,但是为什么呢?

首先定义一个饿汉式单例如下:

 public class Singleton {

// 私有化构造方法,以防止外界使用该构造方法创建新的实例

private Singleton(){

}

// 默认是public,访问可以直接通过Singleton.instance来访问

static Singleton instance = new Singleton();

}

之所以是线程安全的,是因为JVM在类加载的过程,保证了不会初始化多个static对象。类的生命周期主要是:

加载-->验证-->准备-->解析-->初始化-->使用-->卸载

上面的代码,实际上类成员变量instance是在初始化阶段的时候完成初始化,所有的类变量以及static静态代码块,都是在一个叫clinit()的方法里面完成初始化。这一点,使用jclasslib可以看出来:

【Java】设计模式【1.3】-- 为什么饿汉式单例是线程安全的?

clinit()方法是由虚拟机收集的,包含了static变量的赋值操作以及static代码块,所以我们代码中的static Singleton instance = new Singleton();就是在其中。虚拟机本身会保证clinit()代码在多线程并发的时候,只会有一个线程可以访问到,其他的线程都需要等待,并且等到执行的线程结束后才可以接着执行,但是它们不会再进入clinit()方法,所以是线程安全的。我们可以验证一下:

首先改造一下单例:

public class Singleton {

// 私有化构造方法,以防止外界使用该构造方法创建新的实例

private Singleton() {

}

// 默认是public,访问可以直接通过Singleton.instance来访问

static Singleton instance = null;

static {

System.out.println("初始化static模块---开始");

instance = new Singleton();

try {

System.out.println("初始化中...");

Thread.sleep(20 * 1000);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println("初始化static模块----结束");

}

}

测试代码:

import java.io.*;

import java.lang.reflect.InvocationTargetException;

public class SingletonTests {

public static void main(String[] args) throws Exception, InvocationTargetException, InstantiationException, NoSuchMethodException {

Thread thread1 = new Thread(new Runnable() {

public void run() {

System.out.println("线程1开始尝试初始化单例");

Singleton singleton = Singleton.instance;

System.out.println("线程1获取到的单例:" + singleton);

}

});

Thread thread2 = new Thread(new Runnable() {

public void run() {

System.out.println("线程2开始尝试初始化单例");

Singleton singleton = Singleton.instance;

System.out.println("线程2获取到的单例:" + singleton);

}

});

thread1.start();

thread2.start();

}

}

运行结果,一开始运行的时候,我们可以看到线程1进去了static代码块,它在初始化,线程2则在等待。

【Java】设计模式【1.3】-- 为什么饿汉式单例是线程安全的?

待到线程1初始化完成的时候,线程2也不会再进入static代码块,而是和线程1取得同一个对象,由此可见,static代码块实际上就是线程安全的。

【Java】设计模式【1.3】-- 为什么饿汉式单例是线程安全的?

以上是 【Java】设计模式【1.3】-- 为什么饿汉式单例是线程安全的? 的全部内容, 来源链接: utcz.com/a/86874.html

回到顶部