单例模式与线程安全性问题
- 饿汉式(没有线程安全性问题)
- 懒汉式(双重检查加锁解决线程安全性问题)
饿汉式
/**
* 在程序启动或单件模式类被加载的时候,单件模式实例就已经被创建。
* 饿汉式
* 单例模式实例在系统中经常会被用到,饿汉式是一个不错的选择。
*/
public class Singleton {
//私有构造方法
private Singleton () {}
private static Singleton instance = new Singleton();
public static Singleton getInstance() {
return instance;
}
}
懒汉式
/**
* 当程序第一次访问单件模式实例时才进行创建。
* 懒汉式
* 单例模式在系统中会很少用到或者几乎不会用到,那么懒汉式是一个不错的选择
*/
public class Singleton2 {
private Singleton2() {}
//采用volatile避免指令重排序
private static volatile Singleton2 instance;
/**
* 偏向锁(单个线程下访问一直占用,不适用)
* 轻量级锁(多线程下,发生自旋会消耗大量性能,不适用)
* synchronized放弃加在方法上。加在同步代码块上
* 采用双重检查加锁
*
* @return
*/
public static Singleton2 getInstance () {
if(instance == null) {
/**
* 执行顺序:
* 1.检查变量是否被初始化(不去获得锁),如果已被初始化则立即返回。
* 2.获取锁
* 3.再次检查变量是否被初始化,如果还没有则立即返回
*/
synchronized (Singleton2.class) {
if(instance == null) {
instance = new Singleton2();
}
}
}
return instance;
}
}
测试
public class MultiThreadMain {
public static void main(String[] args) {
ExecutorService threadPool = Executors.newFixedThreadPool(20);
for(int i = 0;i<20;i++) {
threadPool.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + ":" +Singleton.getInstance());
}
});
}
threadPool.shutdown();
}
}