单例模式旨在创建一个唯一的对象,一种恶汉式 一种懒汉式。没什么好说的。但是,在多线程下的情景下 就会出现问题
1、单例模式之恶汉式
/**
* @author i
* @create 2019/9/18 20:45
* @Description 恶汉式
*/
public class Singleton {
private static Singleton singleton = new Singleton();
//私有化构造方法
private Singleton(){
}
public static Singleton getInstance(){
return singleton;
}
}
1.2、多线程下使用恶汉式创建对象
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() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+" "+Singleton.getInstance());
}
});
}
}
1.3、结果:从结果中可以看到 我们使用恶汉式多线程下创建对象是没有问题的。因此 就可以下结论 恶汉式情况下 并发使用不会出现问题,
2、单例模式之懒汉式
package com.hblg.t1;
/**
* @author i
* @create 2019/9/18 20:48
* @Description 懒汉式单例实现
*/
public class Singleton2 {
private static Singleton2 instance = null;
public Singleton2(){
}
/***
*
* @return
*/
public static Singleton2 getInstance(){
if(instance == null){
instance = new Singleton2();
}
return instance;
}
}
2.1 多线程下使用懒汉式创建对象
ExecutorService threadPool = Executors.newFixedThreadPool(20);
for (int i = 0; i < 10; i++) {
threadPool.execute(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+" "+Singleton2.getInstance());
}
});
}
threadPool.shutdown();
2.3 结果 分析 我们可以知道,通过多线程懒汉式创建单例出现了问题,原因是什么呢。
if(instance == null){ instance = new Singleton2(); } return instance;
原因就在于此,那就是当多个线程去调用getInstance()方法,由于上面的3行语句 不具有原子性操作,当t1线程进入 第一行
这个时候。线程t2 抢占了cpu执行权获取到了cpu执行时间,去判断时候为空 就会自行创建一个对象。
所有 我们可以通过加锁的方式 来保证数据一致性问题。
/***
* 双重检测加锁
* @return
*/
public static synchronized Singleton2 getInstance(){
if(instance == null){
synchronized (Singleton2.class){
if(instance == null){
instance = new Singleton2(); //指令重排序 加vloatile关键字
}
}
}
return instance;
}
通过上面 可以解决。