1.饿汉式
实现代码:
public class MySingleton {
// 1.饿汉式
private static MySingleton singleton = new MySingleton();
private MySingleton() {
}
public static MySingleton getInstance() {
return singleton;
}
}
开启多线程进行测试:
public class SingletonMain extends Thread {
@Override
public void run() {
System.out.println(MySingleton.getInstance().hashCode());
}
public static void main(String[] args) {
// 创建多线程,一起执行看是否生成同一对象
SingletonMain th1 = new SingletonMain();
SingletonMain th2 = new SingletonMain();
SingletonMain th3 = new SingletonMain();
th1.start();
th2.start();
th3.start();
}
}
结果:
477037219
477037219
477037219
结论:hashCode值一致,说明是同一对象,饿汉式单例模式线程安全
2.懒汉式
实现代码
public class MySingleton {
// 2.懒汉式
private static MySingleton instance = null;
private MySingleton() {
}
public static MySingleton getInstance() throws InterruptedException {
if (instance == null) {
// 创建实例之前可能会有一些准备性的耗时工作
Thread.sleep(300);
instance = new MySingleton();
}
return instance;
}
}
开启多线程进行测试,
public class SingletonMain extends Thread {
@Override
public void run() {
try {
System.out.println(MySingleton.getInstance().hashCode());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
// 创建多线程,一起执行看是否生成同一对象
SingletonMain th1 = new SingletonMain();
SingletonMain th2 = new SingletonMain();
SingletonMain th3 = new SingletonMain();
th1.start();
th2.start();
th3.start();
}
}
结果
1891072390
1139700714
477037219
结论:
不同线程输出的hashCode值不一致,对象不同,懒汉式单例模式线程不安全。
造成不安全的原因:多个线程在进入getInstance方法时,都并没有对象创建出来,导致所有线程都符合(instance == null)的条件,导致对象被重复创建,不构成单例的前提
2-01. 懒汉式改良版-静态同步函数实现
实现代码,增加synchronized关键词,静态同步函数实现线程安全
public class MySingleton {
// 2.懒汉式
private static MySingleton instance = null;
private MySingleton() {
}
public static synchronized MySingleton getInstance() throws InterruptedException {
if (instance == null) {
// 创建实例之前可能会有一些准备性的耗时工作
Thread.sleep(300);
instance = new MySingleton();
}
return instance;
}
}
结果
1891072390
1891072390
1891072390
结论:
静态同步函数可以实现懒汉式单例模式的线程安全,但是将一整个方法都进行加锁,会导致此方法的运行效率降低,继续考虑其他方式进行改良
2-02. 懒汉式改良版-同步代码块实现
实现代码:增加synchronized关键词,对指定代码块加锁,可以大大的提高整个方法的执行效率,下面使用同步代码块实现
public class MySingleton {
// 2.懒汉式
private static MySingleton instance = null;
private MySingleton() {
}
public static MySingleton getInstance() throws InterruptedException {
if (instance == null) {
// 创建实例之前可能会有一些准备性的耗时工作
Thread.sleep(300);
synchronized (MySingleton.class) {
instance = new MySingleton();
}
}
return instance;
}
}
结果
1891072390
756680587
1994444141
结论:目前此种调整方式还不能达到线程安全,继续改良
双检查锁机制
实现代码
public class MySingleton {
// 2.懒汉式
private static MySingleton instance = null;
private MySingleton() {
}
public static MySingleton getInstance() throws InterruptedException {
if (instance == null) {
// 创建实例之前可能会有一些准备性的耗时工作
Thread.sleep(300);
synchronized (MySingleton.class) {
if (instance == null) {
instance = new MySingleton();
}
}
}
return instance;
}
}
结果:
1994444141
1994444141
1994444141
结论:
双检查锁机制可以实现懒汉式单例模式的线程安全,而且这种方式的效率相对于第一种来说是比较高的
3.静态内置类实现单例模式
实现代码
public class MySingleton {
private static class MySingletonHandler {
private static MySingleton singleon = new MySingleton();
}
public static MySingleton getInstance() {
return MySingletonHandler.singleon;
}
}
开启多线程测试
public class SingletonMain extends Thread {
@Override
public void run() {
System.out.println(MySingleton.getInstance().hashCode());
}
public static void main(String[] args) {
// 创建多线程,一起执行看是否生成同一对象
SingletonMain th1 = new SingletonMain();
SingletonMain th2 = new SingletonMain();
SingletonMain th3 = new SingletonMain();
th1.start();
th2.start();
th3.start();
}
}
结果
1740545285
1740545285
1740545285
结论:
静态内置类实现单例模式是线程安全的
4.静态代码块实现单例模式
实现代码:静态代码块中的代码在使用类的时候就已经执行了,所以可以应用静态代码块的这个特性的实现单例设计模式。
public class MySingleton {
// 使用静态代码块实现单例模式
private static MySingleton singleon = null;
private MySingleton() {}
static {
singleon = new MySingleton();
}
public static MySingleton getInstance() {
return singleon;
}
}
结果
1209285429
1209285429
1209285429
结论:静态代码块只在类加载时执行,因而只有一个实体对象,从结果来看,线程也是安全的
5.使用枚举数据类型实现单例模式
实现代码
public class ClassFactory {
private enum MyEnumSingleton {
singletonFactory;
private MySingleton instance;
private MyEnumSingleton() {// 枚举类的构造方法在类加载是被实例化
instance = new MySingleton();
}
public MySingleton getInstance() {
return instance;
}
}
public static MySingleton getInstance() {
return MyEnumSingleton.singletonFactory.getInstance();
}
}
结果
1139700714
1139700714
1139700714
结论:枚举实现单例模式是线程安全的
网友评论