文章目录
- 一、对比总览
- 二、代码
-
- [1. 饿汉式](#1. 饿汉式)
- [2. 饱汉式](#2. 饱汉式)
- [3. 饱汉式-双检锁](#3. 饱汉式-双检锁)
- [4. 静态内部类](#4. 静态内部类)
- [5. 枚举单例](#5. 枚举单例)
- 三、性能对比
一、对比总览
以下是不同单例模式实现方式的特性对比表格。表格从线程安全性、延迟加载、实现复杂度、反序列化安全性、防反射攻击性等多个方面进行考量。
特性 | 饿汉式 | 饱汉式 | 饱汉式-双检锁 | 静态内部类 | 枚举单例(推荐) |
---|---|---|---|---|---|
线程安全性 | √ | × | √ | √ | √ |
延迟加载 | × | √ | √ | √ | × |
实现复杂度 | √ | √ | × | √ | √ |
反序列化安全性 | × | × | × | × | √ |
防反射攻击性 | × | × | × | × | √ |
详细解释
-
线程安全性:
- 饿汉式:类加载时即创建实例(因为instance是static),线程安全。
- 饱汉式:未使用同步机制,线程不安全。
- 饱汉式-双检锁:使用同步块和双重检查锁,线程安全。
- 静态内部类:通过类加载机制,线程安全。
- 枚举单例:JVM确保线程安全。
-
延迟加载:
- 饿汉式:类加载时即创建实例,不具备延迟加载。
- 饱汉式:实例在首次使用时创建,具备延迟加载。
- 饱汉式-双检锁:实例在首次使用时创建,具备延迟加载。
- 静态内部类:实例在首次使用时创建(因为静态内部类只有在使用时才会加载),具备延迟加载。
- 枚举单例:类加载时即创建实例,不具备延迟加载。
-
实现复杂度:
- 饿汉式:实现简单。
- 饱汉式:实现简单。
- 饱汉式-双检锁:实现相对复杂。
- 静态内部类:实现简单。
- 枚举单例:实现简单。
-
反序列化安全性:
- 饿汉式 、饱汉式 、饱汉式-双检锁 、静态内部类 :需要实现
readResolve
方法以防止反序列化创建新实例。 - 枚举单例:天然防止反序列化创建新实例,JVM保证。
- 饿汉式 、饱汉式 、饱汉式-双检锁 、静态内部类 :需要实现
-
防反射攻击性:
- 饿汉式 、饱汉式 、饱汉式-双检锁 、静态内部类:可能通过反射创建新实例。
- 枚举单例 :防止反射攻击,创建新实例时抛出
IllegalArgumentException
。
二、代码
1. 饿汉式
java
public class OrderManager1 {
@Getter
@Setter
private Map<String, TradeOrder> orders = new HashMap<>();
@Getter
private static final OrderManager1 instance = new OrderManager1();
/**
* 添加订单
*
* @param order 顺序
*/
public void addOrder(TradeOrder order) {
orders.put(order.getId(), order);
}
/**
* 获取订单
*
* @param orderId 订单id
* @return {@link TradeOrder}
*/
public TradeOrder getOrder(String orderId) {
return orders.get(orderId);
}
}
2. 饱汉式
java
public class OrderManager2 {
@Getter
@Setter
private Map<String, TradeOrder> orders = new HashMap<>();
private static OrderManager2 instance;
public static OrderManager2 getInstance(){
if (instance == null){
instance = new OrderManager2();
}
return instance;
}
/**
* 添加订单
*
* @param order 顺序
*/
public void addOrder(TradeOrder order) {
orders.put(order.getId(), order);
}
/**
* 获取订单
*
* @param orderId 订单id
* @return {@link TradeOrder}
*/
public TradeOrder getOrder(String orderId) {
return orders.get(orderId);
}
}
3. 饱汉式-双检锁
java
public class OrderManager3 {
@Getter
@Setter
private Map<String, TradeOrder> orders = new HashMap<>();
private static OrderManager3 instance;
public static OrderManager3 getInstance(){
if (instance == null){
synchronized (OrderManager3.class){
if (instance == null){
instance = new OrderManager3();
}
}
instance = new OrderManager3();
}
return instance;
}
/**
* 添加订单
*
* @param order 顺序
*/
public void addOrder(TradeOrder order) {
orders.put(order.getId(), order);
}
/**
* 获取订单
*
* @param orderId 订单id
* @return {@link TradeOrder}
*/
public TradeOrder getOrder(String orderId) {
return orders.get(orderId);
}
}
4. 静态内部类
java
public class OrderManager4 {
@Getter
@Setter
private Map<String, TradeOrder> orders = new HashMap<>();
private static class SingletonHelper{
private static final OrderManager4 INSTANCE = new OrderManager4();
}
public static OrderManager4 getInstance(){
return SingletonHelper.INSTANCE;
}
/**
* 添加订单
*
* @param order 顺序
*/
public void addOrder(TradeOrder order) {
orders.put(order.getId(), order);
}
/**
* 获取订单
*
* @param orderId 订单id
* @return {@link TradeOrder}
*/
public TradeOrder getOrder(String orderId) {
return orders.get(orderId);
}
}
5. 枚举单例
java
public enum OrderManager5 {
INSTANCE;
@Getter
@Setter
private Map<String, TradeOrder> orders = new HashMap<>();
/**
* 添加订单
*
* @param order 顺序
*/
public void addOrder(TradeOrder order) {
orders.put(order.getId(), order);
}
/**
* 获取订单
*
* @param orderId 订单id
* @return {@link TradeOrder}
*/
public TradeOrder getOrder(String orderId) {
return orders.get(orderId);
}
}
三、性能对比
java
package org.dragon.singleton;
import lombok.extern.slf4j.Slf4j;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
@Slf4j
public class SingletonPerformanceTest {
static long timeout = 20; // 超时时间,单位为秒
static int testIterations = 10_000_000; // 测试次数
static int threadCount = 1000; // 并发线程数
static Map<String, HashMap<String, Long>> result = new HashMap<>();
public static void main(String[] args) {
/*
* 多次调用,结果是最后一次调用存入。为什么多次调用,因为单次test不准确,总是靠前的OrderManager跑的快,可能是因为Java某些机制导致的
* 所以多次调用,逐渐平稳。
* */
firstCreationTest();
mulAccessTest();
mulAccessTest();
mulAccessTest();
ConcurrentAccessTest();
ConcurrentAccessTest();
printRes();
ConcurrentAccessTest();
printRes();
ConcurrentAccessTest();
printRes();
}
/**
* 打印结果
*/
private static void printRes(){
ArrayList<String> names = new ArrayList<>();
names.add(OrderManager1.class.getSimpleName());
names.add(OrderManager2.class.getSimpleName());
names.add(OrderManager3.class.getSimpleName());
names.add(OrderManager4.class.getSimpleName());
names.add(OrderManager5.class.getSimpleName());
// 表头
System.out.printf("%-20s%-20s%-25s%-25s%-20s%n", "Singleton Type", "First Creation (ms)", "Multiple Access (ms)", "Concurrent Access (ms)", "Memory Used (MB)");
System.out.println("---------------------------------------------------------------------------------------------------------------");
for (String name : names) {
// 打印结果,转换时间为毫秒
System.out.printf("%-20s%-20.3f%-25.3f%-25.3f%-20.3f%n", name, result.get(name).get("firstCreation") / 1_000_000.0, result.get(name).get("mulAccess") / 1_000_000.0, result.get(name).get("ConcurrentAccess") / 1_000_000.0, 0 / (1024.0 * 1024.0));
}
}
/**
* 首次创建测试
*/
private static void firstCreationTest(){
List<Runnable> tests = new ArrayList<>();
tests.add(()->firstCreation(OrderManager1::getInstance));
tests.add(()->firstCreation(OrderManager2::getInstance));
tests.add(()->firstCreation(OrderManager3::getInstance));
tests.add(()->firstCreation(OrderManager4::getInstance));
tests.add(()->firstCreation(() -> OrderManager5.INSTANCE));
// 随机化测试顺序
Collections.shuffle(tests);
//run
for (Runnable test : tests) {
test.run();
log.info("Complete one test");
try {
Thread.sleep(200);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
/**
* 多次访问测试
*/
private static void mulAccessTest(){
List<Runnable> tests = new ArrayList<>();
tests.add(()->mulAccess(OrderManager1::getInstance, testIterations));
tests.add(()->mulAccess(OrderManager2::getInstance, testIterations));
tests.add(()->mulAccess(OrderManager3::getInstance, testIterations));
tests.add(()->mulAccess(OrderManager4::getInstance, testIterations));
tests.add(()->mulAccess(() -> OrderManager5.INSTANCE, testIterations));
// 随机化测试顺序
Collections.shuffle(tests);
//run
for (Runnable test : tests) {
test.run();
log.info("Complete one test");
try {
Thread.sleep(200);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
/**
* 多线程访问测试
*/
private static void ConcurrentAccessTest(){
List<Runnable> tests = new ArrayList<>();
tests.add(()->ConcurrentAccess(OrderManager1::getInstance, testIterations, threadCount));
tests.add(()->ConcurrentAccess(OrderManager2::getInstance, testIterations, threadCount));
tests.add(()->ConcurrentAccess(OrderManager3::getInstance, testIterations, threadCount));
tests.add(()->ConcurrentAccess(OrderManager4::getInstance, testIterations, threadCount));
tests.add(()->ConcurrentAccess(() -> OrderManager5.INSTANCE, testIterations, threadCount));
// 随机化测试顺序
Collections.shuffle(tests);
//run
for (Runnable test : tests) {
test.run();
log.info("Complete one test");
try {
Thread.sleep(200);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
/**
* 首次创建
*
* @param singletonSupplier 单一供应商
* @return long ns
*/
private static <T> long firstCreation(Supplier<T> singletonSupplier){
// 测试首次创建时间
long startTime = System.nanoTime();
T instance = singletonSupplier.get();
long endTime = System.nanoTime();
long resTime = endTime - startTime;
//save res
String simpleName = instance.getClass().getSimpleName();
HashMap<String, Long> resMap = result.computeIfAbsent(simpleName, k->new HashMap<>());
resMap.put("firstCreation", resTime);
return resTime;
}
/**
* 多次访问
*
* @param singletonSupplier 单一供应商
* @param iterations 迭代
* @return long ns
*/
private static <T> long mulAccess(Supplier<T> singletonSupplier, int iterations){
//预热
for (int i = 0; i < 100_000; i++) {
T instance = singletonSupplier.get();
}
//计算
long startTime = System.nanoTime();
for (int i = 0; i < iterations; i++) {
T instance = singletonSupplier.get();
}
long endTime = System.nanoTime();
long resTime = endTime - startTime;
//save res
String simpleName = singletonSupplier.get().getClass().getSimpleName();
HashMap<String, Long> resMap = result.computeIfAbsent(simpleName, k->new HashMap<>());
resMap.put("mulAccess", resTime);
return resTime;
}
/**
* 并发访问
*
* @param singletonSupplier 单一供应商
* @param iterations 迭代
* @param threadCount 线程数
* @return long ns
*/
private static <T> long ConcurrentAccess(Supplier<T> singletonSupplier, int iterations, int threadCount){
ExecutorService executorService = Executors.newFixedThreadPool(100);
//预热
CountDownLatch latch1 = new CountDownLatch(100);
for (int i = 0; i < threadCount; i++) {
executorService.submit(() -> {
for (int j = 0; j < 100_000; j++) {
T instance = singletonSupplier.get();
}
latch1.countDown();
});
}
try {
boolean completed = latch1.await(timeout, TimeUnit.SECONDS);
if (!completed) {
System.out.println("Concurrent access test for 预热" + singletonSupplier.get().getClass().getSimpleName() + " timed out!");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
//计算
CountDownLatch latch2 = new CountDownLatch(threadCount);
long startTime = System.nanoTime();
for (int i = 0; i < threadCount; i++) {
executorService.submit(() -> {
for (int j = 0; j < iterations; j++) {
T instance = singletonSupplier.get();
}
latch2.countDown();
});
}
try {
boolean completed = latch2.await(timeout, TimeUnit.SECONDS);
if (!completed) {
System.out.println("Concurrent access test for " + singletonSupplier.getClass().getSimpleName() + " timed out!");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
long endTime = System.nanoTime();
long concurrentAccessTime = endTime - startTime;
executorService.shutdown();
//save res
String simpleName = singletonSupplier.get().getClass().getSimpleName();
HashMap<String, Long> resMap = result.computeIfAbsent(simpleName, k->new HashMap<>());
resMap.put("ConcurrentAccess", concurrentAccessTime);
return concurrentAccessTime;
}
}
结果输出如下
txt
[17:15:54.519] [INFO ] org.dragon.singleton.SingletonPerformanceTest 73 firstCreationTest - Complete one test
[17:15:54.730] [INFO ] org.dragon.singleton.SingletonPerformanceTest 73 firstCreationTest - Complete one test
[17:15:54.936] [INFO ] org.dragon.singleton.SingletonPerformanceTest 73 firstCreationTest - Complete one test
[17:15:55.141] [INFO ] org.dragon.singleton.SingletonPerformanceTest 73 firstCreationTest - Complete one test
[17:15:55.347] [INFO ] org.dragon.singleton.SingletonPerformanceTest 73 firstCreationTest - Complete one test
[17:15:55.554] [INFO ] org.dragon.singleton.SingletonPerformanceTest 97 mulAccessTest - Complete one test
[17:15:55.782] [INFO ] org.dragon.singleton.SingletonPerformanceTest 97 mulAccessTest - Complete one test
[17:15:56.007] [INFO ] org.dragon.singleton.SingletonPerformanceTest 97 mulAccessTest - Complete one test
[17:15:56.227] [INFO ] org.dragon.singleton.SingletonPerformanceTest 97 mulAccessTest - Complete one test
[17:15:56.445] [INFO ] org.dragon.singleton.SingletonPerformanceTest 97 mulAccessTest - Complete one test
[17:15:56.669] [INFO ] org.dragon.singleton.SingletonPerformanceTest 97 mulAccessTest - Complete one test
[17:15:56.906] [INFO ] org.dragon.singleton.SingletonPerformanceTest 97 mulAccessTest - Complete one test
[17:15:57.146] [INFO ] org.dragon.singleton.SingletonPerformanceTest 97 mulAccessTest - Complete one test
[17:15:57.376] [INFO ] org.dragon.singleton.SingletonPerformanceTest 97 mulAccessTest - Complete one test
[17:15:57.598] [INFO ] org.dragon.singleton.SingletonPerformanceTest 97 mulAccessTest - Complete one test
[17:15:57.818] [INFO ] org.dragon.singleton.SingletonPerformanceTest 97 mulAccessTest - Complete one test
[17:15:58.054] [INFO ] org.dragon.singleton.SingletonPerformanceTest 97 mulAccessTest - Complete one test
[17:15:58.276] [INFO ] org.dragon.singleton.SingletonPerformanceTest 97 mulAccessTest - Complete one test
[17:15:58.495] [INFO ] org.dragon.singleton.SingletonPerformanceTest 97 mulAccessTest - Complete one test
[17:15:58.716] [INFO ] org.dragon.singleton.SingletonPerformanceTest 97 mulAccessTest - Complete one test
[17:15:59.430] [INFO ] org.dragon.singleton.SingletonPerformanceTest 121 ConcurrentAccessTest - Complete one test
[17:15:59.658] [INFO ] org.dragon.singleton.SingletonPerformanceTest 121 ConcurrentAccessTest - Complete one test
[17:16:02.737] [INFO ] org.dragon.singleton.SingletonPerformanceTest 121 ConcurrentAccessTest - Complete one test
[17:16:08.533] [INFO ] org.dragon.singleton.SingletonPerformanceTest 121 ConcurrentAccessTest - Complete one test
[17:16:13.700] [INFO ] org.dragon.singleton.SingletonPerformanceTest 121 ConcurrentAccessTest - Complete one test
[17:16:19.432] [INFO ] org.dragon.singleton.SingletonPerformanceTest 121 ConcurrentAccessTest - Complete one test
[17:16:24.632] [INFO ] org.dragon.singleton.SingletonPerformanceTest 121 ConcurrentAccessTest - Complete one test
[17:16:30.366] [INFO ] org.dragon.singleton.SingletonPerformanceTest 121 ConcurrentAccessTest - Complete one test
[17:16:35.516] [INFO ] org.dragon.singleton.SingletonPerformanceTest 121 ConcurrentAccessTest - Complete one test
[17:16:40.431] [INFO ] org.dragon.singleton.SingletonPerformanceTest 121 ConcurrentAccessTest - Complete one test
Singleton Type First Creation (ms) Multiple Access (ms) Concurrent Access (ms) Memory Used (MB)
---------------------------------------------------------------------------------------------------------------
OrderManager1 0.010 16.848 4928.236 0.000
OrderManager2 0.010 18.592 5504.781 0.000
OrderManager3 0.009 19.127 5513.309 0.000
OrderManager4 0.241 18.772 4920.940 0.000
OrderManager5 0.117 16.637 4704.835 0.000
[17:16:45.002] [INFO ] org.dragon.singleton.SingletonPerformanceTest 121 ConcurrentAccessTest - Complete one test
[17:16:48.982] [INFO ] org.dragon.singleton.SingletonPerformanceTest 121 ConcurrentAccessTest - Complete one test
[17:16:52.778] [INFO ] org.dragon.singleton.SingletonPerformanceTest 121 ConcurrentAccessTest - Complete one test
[17:16:57.834] [INFO ] org.dragon.singleton.SingletonPerformanceTest 121 ConcurrentAccessTest - Complete one test
[17:17:02.298] [INFO ] org.dragon.singleton.SingletonPerformanceTest 121 ConcurrentAccessTest - Complete one test
Singleton Type First Creation (ms) Multiple Access (ms) Concurrent Access (ms) Memory Used (MB)
---------------------------------------------------------------------------------------------------------------
OrderManager1 0.010 16.848 4217.333 0.000
OrderManager2 0.010 18.592 4340.869 0.000
OrderManager3 0.009 19.127 4824.581 0.000
OrderManager4 0.241 18.772 3743.032 0.000
OrderManager5 0.117 16.637 3558.995 0.000
[17:17:06.778] [INFO ] org.dragon.singleton.SingletonPerformanceTest 121 ConcurrentAccessTest - Complete one test
[17:17:11.231] [INFO ] org.dragon.singleton.SingletonPerformanceTest 121 ConcurrentAccessTest - Complete one test
[17:17:15.733] [INFO ] org.dragon.singleton.SingletonPerformanceTest 121 ConcurrentAccessTest - Complete one test
[17:17:20.812] [INFO ] org.dragon.singleton.SingletonPerformanceTest 121 ConcurrentAccessTest - Complete one test
[17:17:25.837] [INFO ] org.dragon.singleton.SingletonPerformanceTest 121 ConcurrentAccessTest - Complete one test
Singleton Type First Creation (ms) Multiple Access (ms) Concurrent Access (ms) Memory Used (MB)
---------------------------------------------------------------------------------------------------------------
OrderManager1 0.010 16.848 4281.649 0.000
OrderManager2 0.010 18.592 4849.279 0.000
OrderManager3 0.009 19.127 4782.224 0.000
OrderManager4 0.241 18.772 4267.228 0.000
OrderManager5 0.117 16.637 4233.907 0.000
进程已结束,退出代码为 0
可以去多跑几次,基本上最后一种枚举单例,性能属于最好的一批。并且也最安全。