熟悉Java的朋友应该对单例设计模式了解的不少,比如我们会发现Spring中默认交给容器管理的对象都是单例的,除非你手动的设置。那么Spring是如何保证容器中的Bean对象只创建一次呢?下面,我们就分析一下单设计及模式与并发碰撞在一起会出现怎样的火花。
懒汉模式和饿汉模式得区别:
懒汉模式就是懒,不用它就不创建,等到要用的时候才创建(赶晚不赶早)
饿汉模式就是饿死鬼,还没到用到得时候他就创建出来,就像还没有到吃饭的时间,就早早把饭做好了。(赶早不赶晚)。
一.懒汉模式
1.懒汉设计模式(一挡!)。
/**
* 懒汉模式(一挡)
*
*/
@Slf4j
@UnThreadSafe//这两个注解你不需要关心
public class test_Singleton_lazy{
//获取实例对象
@Test
public void fun1(){
/**
* 下面的意思就是开50个线程,并发的获取Singleton_Lazy的实例
*
*/
ExecutorService executorService = Executors.newCachedThreadPool();
for(int i= 0 ; i< 50 ; i++){
executorService.execute(()->{
System.out.println("singleton_lazy1的HashCode为:"+Singleton_Lazy.getSingletion().hashCode());
});
}
}
}
//最基本的单例设计模式,也是我们最先接触到的,在单线称下可以正确的运行,但是高并发下,就会出错!
class Singleton_Lazy {
//构造函数私有化
private Singleton_Lazy(){
}
//创建成员变量
private static Singleton_Lazy singleton_lazy=null;
//静态方法获取目标对象
public static Singleton_Lazy getSingletion(){
if(singleton_lazy == null){
singleton_lazy = new Singleton_Lazy();
}
return singleton_lazy;
}
}
高并发下的测试结果:
解释:上面我们开了50个线程同时获取Singleton_Lazy的实例,我们可以模拟一下线程。当一条线程通过下面的判断条件进入if块后,在还没来得及改变singleton_lazy的值或线程工作区虽然改变了但是还未及时刷新回内存的时候,另一个线程也通过了if判断,进入了if语句块内部,这时,后一个线程和前一个线程将持有不同的返回对象,单例模式被高并发破环!
if(singleton_lazy == null){
singleton_lazy = new Singleton_Lazy();
}
下面我们对上面的懒汉设计模式进行升级!
2.懒汉设计模式(二挡!)
/**
*
* 单例设计模式,懒汉式(二挡)
*/
@Slf4j
@UnThreadSafe
public class test_Singleton_lazy_01 {
@Test
public void fun1(){
/**
* 下面的意思就是开50个线