## 一、单例模式实现
这里我们通过**懒汉模式**与**Double Check**实现线程安全的单例模式,代码如下:
```
public class Singleton {
// 定义无参构造器
private Singleton(){}
// volatile保证多个线程从主存访问
private static volatile Singleton singleton;
public static Singleton getInstance(){
// 判断对象是否已创建
if (Objects.isNull(singleton)){
// 锁住class对象 对象只有一个 因此只有一个线程拥有monitor锁
synchronized (Singleton.class){
// 再次判断对象是否已经创建 避免线程等待的时候 其他线程已经创建该对象
if (Objects.isNull(singleton)){
singleton = new Singleton();
}
}
}
return singleton;
}
}
```
代码的具体含义已经在文中注释,这里我们补充说下,`synchronized`保证只有一个线程在对象为空时进行创建,`volatile`保证判断单例对象(`Singleton`)是否为空时的可见性,避免对象未初始化完成就返回。
线程安全的单例模式还可以通过**静态内部类**、**枚举**等方式实现,这里我们暂不详述。
## 二、并发模拟测试
这里我们使用线程池进行并发模拟,并通过`CompletableFuture`进行异步任务编排。
首先我们自定义线程池:
```
/**
* @author winsonWu
* @Description: thread pool creating util
* @date Date : 2021.04.11 21:20
*/
@Configuration
public class ThreadPoolCreator {
/**
* 核心线程数
* 如果执行CPU密集任务,则尽量不超过操作系统核数2倍
* 如果IO密集型可适当加大
* 具体设置根据压测结果决定
*/
private static int corePoolSize = Runtime.getRuntime().availableProcessors() * 3;
/**
* 最大线程数 避免内存交换 设置为核心核心线程数
*/
private static int maximumPoolSize = corePoolSize;
/**
* 最大空闲时间
*/
private static long keepAliveTime = 1;
/**
* 最大空闲时间单位
*/
private static TimeUnit unit = TimeUnit.HOURS;
/**
* 使用有界队列,避免内存溢出
*/
private static BlockingQueue
/**
* 默认线程工厂,建议自定义,并设置线程名称获取规则
*/
private static ThreadFactory threadFactory = Executors.defaultThreadFactory();
/**
* 拒绝策略
*/
private static RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();
@Bean
public ThreadPoolExecutor threadPoolExecutor(){
return new ThreadPoolExecutor(
corePoolSize,
maximumPoolSize,
keepAliveTime, unit,
workQueue,
threadFactory,
handler);
}
}
```
接下来我们编写单元测试:
```
/**
* @Author winsonWu
* @Description: TODO
* @date Date : 2022.04.11 21:57
**/
@SpringBootTest
public class SingletonTest {
@Resource
private ThreadPoolExecutor threadPoolExecutor;
@BeforeAll
public static void prepareEnv(){
}
@Test
public void testSingle(){
List
List
for (int i=0; i<1000; i++){
CompletableFuture
futures.add(future);
}
CompletableFuture
.allOf(futures.toArray(new CompletableFuture[futures.size()]))
.whenComplete((v, t)-> futures.forEach(eachFuture -> {
singletons.add(eachFuture.getNow(null));
})).join();
// 放入集合去重后 最终对象数量为1
Assertions.assertEquals(singletons.stream().collect(Collectors.toSet()).size(), 1);
}
}
```
执行单元测试:
![1649739965(1).png](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c59335d732fa4cf4bda8ac93b4eefd6f~tplv-k3u1fbpfcp-watermark.image?)
断言`Assertions.assertEquals(singletons.stream().collect(Collectors.toSet()).size(), 1);
`通过。
## 三、参考资料
- [单例模式](https://baike.baidu.com/item/%E5%8D%95%E4%BE%8B%E6%A8%A1%E5%BC%8F/5946627?fr=aladdin)
- [CompletableFuture](https://nowjava.com/docs/java-jdk-14/api/java.base/java/util/concurrent/CompletableFuture.html)