1.场景问题解决
1.1 场景描述
有些对象我们只需要一个:线程池、缓存、硬件设备等
如果多个实例会有造成冲突、结果的不一致性等问题
2.用设计模式改进
2.1 源码
2.1.1 饿汉式单例模式
/**
饿汉式单例模式-不会出现线程安全模式
*/
public class SingletonHunger {
// 私有化构造方法
private SingletonHunger () {}
//类加载时就产生了instance对象
private static SingletonHunger instance = new SingletonHunger();
public static SingletonHunger getInstance() {
return instance;
}
}
2.1.2 懒汉式–会有线程安全问题
//出现了非原子性操作-会有多线程安全问题
public class SingletonLazy1 {
private SingletonLazy1() {
}
private static volatile SingletonLazy1 instance;
//这里出现了非原子性操作-会有多线程问题
public static SingletonLazy1 getInstance() {
if (instance == null) {
instance = new SingletonLazy1();
}
return instance;
}
//出现多线程安全的条件如下:饿汉式不会出现线程安全问题
// 多线程的环境下
// 必须有共享资源
// 对资源进行非原子性操作
}
2.1.3 懒汉式-同步-synchronized
public class SingletonLazy2 {
private SingletonLazy2() {
}
private static volatile SingletonLazy2 instance;
/**
* 虽然有synchronized具有如下特性:
* 偏向锁(但是针对单线程访问synchronized方法)
* 轻量锁-第二个线程也能进入, 自旋,自旋还消耗cpu资源(相当于while true),还不如wait,wait不消耗cpu资源
* 所以如果synchronized放在方法中,对性能也不会很好
*
* 分析出现线程不同步的场景:只有第一次加载的时候(多线程同时加载)才可能出现线程不同步的情况.优化方式查看SingletonLazy3
*/
public static synchronized SingletonLazy2 getInstance() throws InterruptedException {
if (instance == null) {
Thread.sleep(100);
instance = new SingletonLazy2(); // 指令重排序
}
return instance;
}
}
2.1.4 懒汉式-同步-双重检查再加锁
public class SingletonLazy3 {
private SingletonLazy3() {}
//禁止指令重排序
private static volatile SingletonLazy3 instance;
/**
* 分析出现线程不同步的场景:只有第一次加载的时候(多线程同时加载)才可能出现线程不同步的情况.
*
* 从普通synchronized升级到 SingletonLazy2 在升级到 双重锁,在升级到 volatile
*
* 双重检查(两次判断instance == null)再加锁
*/
public static SingletonLazy3 getInstance () {
// 自旋 while(true)
if(instance == null) {
synchronized (SingletonLazy3.class) {
if(instance == null) {
instance = new SingletonLazy3();
/*在双重检查加锁只有,还可能会有指令重排序的问题:
申请一块内存空间 // 1
在这块空间里实例化对象 // 2
instance的引用指向这块空间地址 // 3
以上可能1->2->3,也可能1->3-2,
如果1,3,2的话则会造成判断instance==null的时候,判断结果不为空,但是实际上没有实例化对象.
解决办法就是用 volatile(不会出现指令重排序问题)
*/
}
}
}
return instance;
}
}
3.设计模式总结
3.1 定义
确保一个类最多只有一个实例,并提供一个全局访问点
4. 设计模式使用场景及注意
有些对象我们只需要一个:线程池、缓存、硬件设备等
如果多个实例会有造成冲突、结果的不一致性等问题
5.参考文章
内容总计于HeadFirst设计模式及相关视频
并发编程5-单例