特点
- 系统内有且只有一个实例对象;
- 单例类的构造方法为私有的,自己持有自己的一个实例对象;
- 开放获取实例对象的方法;
分类
单例模式主要可分为饿汉式、饱汉式、枚举式、内部类、容器式;测试代码均采用多线程测试方式。
饿汉式
在类加载时,创建一个实例,当外部获取时,直接返回创建的实例。这种方式占用了一定的内存空间、节约了在使用时创建对象的时间和资源消耗。也不用担心线程安全的问题。
public class HungrySingleton {
private HungrySingleton(){}
private static final HungrySingleton INSTANCE = new HungrySingleton();
public HungrySingleton getInstance(){
return INSTANCE;
}
}
测试代码
@Test
public void testHungrySingleton() throws InterruptedException {
ExecutorService executorService = Executors.newFixedThreadPool(10);
for (int i = 0; i < 10; i++) {
executorService.submit(() ->{
HungrySingleton instance = HungrySingleton.getInstance();
log.info("线程 {} 获取到的实例: {}",Thread.currentThread().getName(),instance);
});
}
}
说明:创建10个线程分别获取HungrySingleton实例,进而知晓获取到的10个实例对象的内存地址:
2021-03-04 13:24:16.717 INFO 8428 --- [pool-1-thread-4] org.example.singleton.SingletonTest : 线程 pool-1-thread-4 获取到的实例: org.example.singleton.HungrySingleton@1479e6cc 2021-03-04 13:24:16.714 INFO 8428 --- [pool-1-thread-1] org.example.singleton.SingletonTest : 线程 pool-1-thread-1 获取到的实例: org.example.singleton.HungrySingleton@1479e6cc 2021-03-04 13:24:16.714 INFO 8428 --- [pool-1-thread-5] org.example.singleton.SingletonTest : 线程 pool-1-thread-5 获取到的实例: org.example.singleton.HungrySingleton@1479e6cc 2021-03-04 13:24:16.714 INFO 8428 --- [pool-1-thread-3] org.example.singleton.SingletonTest : 线程 pool-1-thread-3 获取到的实例: org.example.singleton.HungrySingleton@1479e6cc 2021-03-04 13:24:16.716 INFO 8428 --- [pool-1-thread-2] org.example.singleton.SingletonTest : 线程 pool-1-thread-2 获取到的实例: org.example.singleton.HungrySingleton@1479e6cc 2021-03-04 13:24:16.716 INFO 8428 --- [ool-1-thread-10] org.example.singleton.SingletonTest : 线程 pool-1-thread-10 获取到的实例: org.example.singleton.HungrySingleton@1479e6cc 2021-03-04 13:24:16.716 INFO 8428 --- [pool-1-thread-9] org.example.singleton.SingletonTest : 线程 pool-1-thread-9 获取到的实例: org.example.singleton.HungrySingleton@1479e6cc 2021-03-04 13:24:16.717 INFO 8428 --- [pool-1-thread-8] org.example.singleton.SingletonTest : 线程 pool-1-thread-8 获取到的实例: org.example.singleton.HungrySingleton@1479e6cc 2021-03-04 13:24:16.716 INFO 8428 --- [pool-1-thread-7] org.example.singleton.SingletonTest : 线程 pool-1-thread-7 获取到的实例: org.example.singleton.HungrySingleton@1479e6cc 2021-03-04 13:24:16.714 INFO 8428 --- [pool-1-thread-6] org.example.singleton.SingletonTest : 线程 pool-1-thread-6 获取到的实例: org.example.singleton.HungrySingleton@1479e6cc
获取的10个实例对象内存地址相同。
懒汉式
也叫延迟加载方式,当系统需要使用时,创建实例。这种方式在类加载时,只是声明了一个空间,但并为创建实例对象,当进程内首次获取对象时,会先创建一个实例,然后返回,后续则返回第一次创建的实例。但是这种模式是线程不安全的,当出现并发时,可能会创建多个实例对象,所以需要引入锁机制来保证线程安全,本文的处理方式是 加入常用的双重检验锁。
public class LazySingleton {
private LazySingleton(){}
private static LazySingleton lazySingleton;
public static LazySingleton getInstance (){
if (lazySingleton == null){
lazySingleton = new LazySingleton();
}
return lazySingleton;
}
}
测试代码
@Test
public void testLazyWithNoDoubleLockSingleton() throws InterruptedException {
CountDownLatch cdl = new CountDownLatch(10);
ExecutorService executorService = Executors.newFixedThreadPool(10);
for (int i = 0; i < 10; i++) {
executorService.submit(() ->{
try {
//等待
cdl.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
LazySingleton instance = LazySingleton.getInstance();
log.info("线程 {} 获取到的实例: {}",Thread.currentThread().getName(),instance);
});
//计数器-1
cdl.countDown();
}
executorService.awaitTermination(5, TimeUnit.SECONDS);
executorService.shutdown();
}
说明:
2021-03-04 13:41:00.361 INFO 14632 --- [pool-1-thread-2] org.example.singleton.SingletonTest : 线程 pool-1-thread-2 获取到的实例: org.example.singleton.LazySingleton@447e4749 2021-03-04 13:41:00.362 INFO 14632 --- [ool-1-thread-10] org.example.singleton.SingletonTest : 线程 pool-1-thread-10 获取到的实例: org.example.singleton.LazySingleton@447e4749 2021-03-04 13:41:00.363 INFO 14632 --- [pool-1-thread-1] org.example.singleton.SingletonTest : 线程 pool-1-thread-1 获取到的实例: org.example.singleton.LazySingleton@447e4749 2021-03-04 13:41:00.363 INFO 14632 --- [pool-1-thread-8] org.example.singleton.SingletonTest : 线程 pool-1-thread-8 获取到的实例: org.example.singleton.LazySingleton@447e4749 2021-03-04 13:41:00.362 INFO 14632 --- [pool-1-thread-7] org.example.singleton.SingletonTest : 线程 pool-1-thread-7 获取到的实例: org.example.singleton.LazySingleton@447e4749 2021-03-04 13:41:00.362 INFO 14632 --- [pool-1-thread-3] org.example.singleton.SingletonTest : 线程 pool-1-thread-3 获取到的实例: org.example.singleton.LazySingleton@447e4749 2021-03-04 13:41:00.362 INFO 14632 --- [pool-1-thread-4] org.example.singleton.SingletonTest : 线程 pool-1-thread-4 获取到的实例: org.example.singleton.LazySingleton@447e4749 2021-03-04 13:41:00.362 INFO 14632 --- [pool-1-thread-9] org.example.singleton.SingletonTest : 线程 pool-1-thread-9 获取到的实例: org.example.singleton.LazySingleton@447e4749 2021-03-04 13:41:00.362 INFO 14632 --- [pool-1-thread-5] org.example.singleton.SingletonTest : 线程 pool-1-thread-5 获取到的实例: org.example.singleton.LazySingleton@1bf38d27 2021-03-04 13:41:00.362 INFO 14632 --- [pool-1-thread-6] org.example.singleton.SingletonTest : 线程 pool-1-thread-6 获取到的实例: org.example.singleton.LazySingleton@447e4749
由日志信息可知:
pool-1-thread-5
获取到的实例的地址与其他线程不相同,说明此种单例模式,线程不安全。
为了提升线程安全性,需要对代码进行改造,代码中引入了双重检验锁
public class LazyWithDoubleLockSingleton {
private LazyWithDoubleLockSingleton(){}
private static LazyWithDoubleLockSingleton lazySingleton;
public static LazyWithDoubleLockSingleton getInstance (){
if (lazySingleton == null){
synchronized (LazyWithDoubleLockSingleton.class){
if (lazySingleton == null){
lazySingleton = new LazyWithDoubleLockSingleton();
}
}
}
return lazySingleton;
}
}
测试代码
@Test public void testLazyWithDoubleLockSingleton() throws InterruptedException { CountDownLatch cdl = new CountDownLatch(20); ExecutorService executorService = Executors.newFixedThreadPool(20); for (int i = 0; i < 20; i++) { executorService.submit(() ->{ try { cdl.await(); } catch (InterruptedException e) { e.printStackTrace(); } LazyWithDoubleLockSingleton instance = LazyWithDoubleLockSingleton.getInstance(); log.info("线程 {} 获取到的实例: {}",Thread.currentThread().getName(),instance); }); cdl.countDown(); } executorService.awaitTermination(5, TimeUnit.SECONDS); executorService.shutdown(); }
说明:开启20个线程,获取实例日志信息:
2021-03-04 14:14:45.560 INFO 11008 --- [ool-1-thread-11] org.example.singleton.SingletonTest : 线程 pool-1-thread-11 获取到的实例: org.example.singleton.LazyWithDoubleLockSingleton@2bde9446 2021-03-04 14:14:45.561 INFO 11008 --- [ool-1-thread-20] org.example.singleton.SingletonTest : 线程 pool-1-thread-20 获取到的实例: org.example.singleton.LazyWithDoubleLockSingleton@2bde9446 2021-03-04 14:14:45.560 INFO 11008 --- [ool-1-thread-15] org.example.singleton.SingletonTest : 线程 pool-1-thread-15 获取到的实例: org.example.singleton.LazyWithDoubleLockSingleton@2bde9446 2021-03-04 14:14:45.560 INFO 11008 --- [pool-1-thread-2] org.example.singleton.SingletonTest : 线程 pool-1-thread-2 获取到的实例: org.example.singleton.LazyWithDoubleLockSingleton@2bde9446 2021-03-04 14:14:45.560 INFO 11008 --- [pool-1-thread-4] org.example.singleton.SingletonTest : 线程 pool-1-thread-4 获取到的实例: org.example.singleton.LazyWithDoubleLockSingleton@2bde9446 2021-03-04 14:14:45.562 INFO 11008 --- [pool-1-thread-8] org.example.singleton.SingletonTest : 线程 pool-1-thread-8 获取到的实例: org.example.singleton.LazyWithDoubleLockSingleton@2bde9446 2021-03-04 14:14:45.559 INFO 11008 --- [pool-1-thread-5] org.example.singleton.SingletonTest : 线程 pool-1-thread-5 获取到的实例: org.example.singleton.LazyWithDoubleLockSingleton@2bde9446 2021-03-04 14:14:45.559 INFO 11008 --- [pool-1-thread-6] org.example.singleton.SingletonTest : 线程 pool-1-thread-6 获取到的实例: org.example.singleton.LazyWithDoubleLockSingleton@2bde9446 2021-03-04 14:14:45.559 INFO 11008 --- [pool-1-thread-3] org.example.singleton.SingletonTest : 线程 pool-1-thread-3 获取到的实例: org.example.singleton.LazyWithDoubleLockSingleton@2bde9446 2021-03-04 14:14:45.559 INFO 11008 --- [ool-1-thread-18] org.example.singleton.SingletonTest : 线程 pool-1-thread-18 获取到的实例: org.example.singleton.LazyWithDoubleLockSingleton@2bde9446 2021-03-04 14:14:45.559 INFO 11008 --- [ool-1-thread-19] org.example.singleton.SingletonTest : 线程 pool-1-thread-19 获取到的实例: org.example.singleton.LazyWithDoubleLockSingleton@2bde9446 2021-03-04 14:14:45.559 INFO 11008 --- [pool-1-thread-7] org.example.singleton.SingletonTest : 线程 pool-1-thread-7 获取到的实例: org.example.singleton.LazyWithDoubleLockSingleton@2bde9446 2021-03-04 14:14:45.564 INFO 11008 --- [ool-1-thread-17] org.example.singleton.SingletonTest : 线程 pool-1-thread-17 获取到的实例: org.example.singleton.LazyWithDoubleLockSingleton@2bde9446 2021-03-04 14:14:45.558 INFO 11008 --- [ool-1-thread-12] org.example.singleton.SingletonTest : 线程 pool-1-thread-12 获取到的实例: org.example.singleton.LazyWithDoubleLockSingleton@2bde9446 2021-03-04 14:14:45.564 INFO 11008 --- [pool-1-thread-1] org.example.singleton.SingletonTest : 线程 pool-1-thread-1 获取到的实例: org.example.singleton.LazyWithDoubleLockSingleton@2bde9446 2021-03-04 14:14:45.564 INFO 11008 --- [ool-1-thread-10] org.example.singleton.SingletonTest : 线程 pool-1-thread-10 获取到的实例: org.example.singleton.LazyWithDoubleLockSingleton@2bde9446 2021-03-04 14:14:45.564 INFO 11008 --- [ool-1-thread-14] org.example.singleton.SingletonTest : 线程 pool-1-thread-14 获取到的实例: org.example.singleton.LazyWithDoubleLockSingleton@2bde9446 2021-03-04 14:14:45.560 INFO 11008 --- [pool-1-thread-9] org.example.singleton.SingletonTest : 线程 pool-1-thread-9 获取到的实例: org.example.singleton.LazyWithDoubleLockSingleton@2bde9446 2021-03-04 14:14:45.560 INFO 11008 --- [ool-1-thread-16] org.example.singleton.SingletonTest : 线程 pool-1-thread-16 获取到的实例: org.example.singleton.LazyWithDoubleLockSingleton@2bde9446 2021-03-04 14:14:45.560 INFO 11008 --- [ool-1-thread-13] org.example.singleton.SingletonTest : 线程 pool-1-thread-13 获取到的实例: org.example.singleton.LazyWithDoubleLockSingleton@2bde9446
由以上日志信息可知,加了双重检验锁后,20个线程获取的实例均相同。
枚举式
枚举式单例,线程安全
- 定义一个类
Person
public class Person {
private String name;
public Person(String name) {
this.name = name;
}
}
- 定义枚举
@Getter
public enum EnumSingleton {
PERSON(new Person("befory"));
private Person person;
EnumSingleton(Person person) {
this.person = person;
}
}
测试代码
@Test
public void testEnumSingleton() throws InterruptedException {
CountDownLatch cdl = new CountDownLatch(10);
ExecutorService executorService = Executors.newFixedThreadPool(10);
for (int i = 0; i < 10; i++) {
executorService.submit(() ->{
try {
cdl.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
Person instance = EnumSingleton.PERSON.getPerson();
log.info("线程 {} 获取到的实例: {}",Thread.currentThread().getName(),instance);
});
cdl.countDown();
}
executorService.awaitTermination(5, TimeUnit.SECONDS);
executorService.shutdown();
}
运行日志信息:
2021-03-04 14:17:10.939 INFO 11688 --- [pool-1-thread-3] org.example.singleton.SingletonTest : 线程 pool-1-thread-3 获取到的实例: org.example.singleton.Person@34f864c5 2021-03-04 14:17:10.938 INFO 11688 --- [pool-1-thread-1] org.example.singleton.SingletonTest : 线程 pool-1-thread-1 获取到的实例: org.example.singleton.Person@34f864c5 2021-03-04 14:17:10.939 INFO 11688 --- [pool-1-thread-8] org.example.singleton.SingletonTest : 线程 pool-1-thread-8 获取到的实例: org.example.singleton.Person@34f864c5 2021-03-04 14:17:10.939 INFO 11688 --- [pool-1-thread-5] org.example.singleton.SingletonTest : 线程 pool-1-thread-5 获取到的实例: org.example.singleton.Person@34f864c5 2021-03-04 14:17:10.940 INFO 11688 --- [pool-1-thread-6] org.example.singleton.SingletonTest : 线程 pool-1-thread-6 获取到的实例: org.example.singleton.Person@34f864c5 2021-03-04 14:17:10.939 INFO 11688 --- [pool-1-thread-9] org.example.singleton.SingletonTest : 线程 pool-1-thread-9 获取到的实例: org.example.singleton.Person@34f864c5 2021-03-04 14:17:10.939 INFO 11688 --- [pool-1-thread-7] org.example.singleton.SingletonTest : 线程 pool-1-thread-7 获取到的实例: org.example.singleton.Person@34f864c5 2021-03-04 14:17:10.938 INFO 11688 --- [ool-1-thread-10] org.example.singleton.SingletonTest : 线程 pool-1-thread-10 获取到的实例: org.example.singleton.Person@34f864c5 2021-03-04 14:17:10.938 INFO 11688 --- [pool-1-thread-4] org.example.singleton.SingletonTest : 线程 pool-1-thread-4 获取到的实例: org.example.singleton.Person@34f864c5 2021-03-04 14:17:10.938 INFO 11688 --- [pool-1-thread-2] org.example.singleton.SingletonTest : 线程 pool-1-thread-2 获取到的实例: org.example.singleton.Person@34f864c5
结论:地址相同
内部类
也叫登记式,类部拥有一个静态内部类,静态内部类中拥有一个实例化的对象,一个类中可以拥有多个静态内部类,它可以实现多种策略的单例模式,由于静态内部类加载机制,这种方式属于延迟加载(在使用时加载),但同时它又保证了线程安全。
public class InnerSingleton {
private InnerSingleton(){}
public static class Holder{
public static InnerSingleton INSTANCE = new InnerSingleton();
}
}
测试代码
@Test
public void testInnerSingleton() throws InterruptedException {
CountDownLatch cdl = new CountDownLatch(10);
ExecutorService executorService = Executors.newFixedThreadPool(10);
for (int i = 0; i < 10; i++) {
executorService.submit(() ->{
try {
cdl.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
InnerSingleton instance = InnerSingleton.Holder.INSTANCE;
log.info("线程 {} 获取到的实例: {}",Thread.currentThread().getName(),instance);
});
cdl.countDown();
}
executorService.awaitTermination(5, TimeUnit.SECONDS);
executorService.shutdown();
}
运行日志
2021-03-04 14:24:59.135 INFO 14160 --- [pool-1-thread-8] org.example.singleton.SingletonTest : 线程 pool-1-thread-8 获取到的实例: org.example.singleton.InnerSingleton@5c1be49
2021-03-04 14:24:59.134 INFO 14160 --- [pool-1-thread-1] org.example.singleton.SingletonTest : 线程 pool-1-thread-1 获取到的实例: org.example.singleton.InnerSingleton@5c1be49
2021-03-04 14:24:59.135 INFO 14160 --- [pool-1-thread-3] org.example.singleton.SingletonTest : 线程 pool-1-thread-3 获取到的实例: org.example.singleton.InnerSingleton@5c1be49
2021-03-04 14:24:59.135 INFO 14160 --- [pool-1-thread-2] org.example.singleton.SingletonTest : 线程 pool-1-thread-2 获取到的实例: org.example.singleton.InnerSingleton@5c1be49
2021-03-04 14:24:59.136 INFO 14160 --- [pool-1-thread-9] org.example.singleton.SingletonTest : 线程 pool-1-thread-9 获取到的实例: org.example.singleton.InnerSingleton@5c1be49
2021-03-04 14:24:59.135 INFO 14160 --- [pool-1-thread-5] org.example.singleton.SingletonTest : 线程 pool-1-thread-5 获取到的实例: org.example.singleton.InnerSingleton@5c1be49
2021-03-04 14:24:59.135 INFO 14160 --- [pool-1-thread-6] org.example.singleton.SingletonTest : 线程 pool-1-thread-6 获取到的实例: org.example.singleton.InnerSingleton@5c1be49
2021-03-04 14:24:59.135 INFO 14160 --- [pool-1-thread-7] org.example.singleton.SingletonTest : 线程 pool-1-thread-7 获取到的实例: org.example.singleton.InnerSingleton@5c1be49
2021-03-04 14:24:59.135 INFO 14160 --- [pool-1-thread-4] org.example.singleton.SingletonTest : 线程 pool-1-thread-4 获取到的实例: org.example.singleton.InnerSingleton@5c1be49
2021-03-04 14:24:59.135 INFO 14160 --- [ool-1-thread-10] org.example.singleton.SingletonTest : 线程 pool-1-thread-10 获取到的实例: org.example.singleton.InnerSingleton@5c1be49
日志信息显示 内存地址相同
容器式
容器式单例与其他几种类型单例不同,容器式单例需要先创建一个容器的实例,容器是单例。这种方式也是springIOC容器实现的一种方式
public class ContainerSingleton {
// 定义容器
private static final ConcurrentHashMap<String,Person> CONTAINER = new ConcurrentHashMap<>();
public static Person getInstance(String name){
if (CONTAINER.containsKey(name)){
return CONTAINER.get(name);
}
Person person = new Person("befory");
CONTAINER.put(name,person);
return person;
}
}
测试代码
@Test
public void testContainerSingleton() throws InterruptedException {
CountDownLatch cdl = new CountDownLatch(10);
ExecutorService executorService = Executors.newFixedThreadPool(10);
for (int i = 0; i < 10; i++) {
executorService.submit(() ->{
try {
cdl.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
Person instance = ContainerSingleton.getInstance("befory");
log.info("线程 {} 获取到的实例: {}",Thread.currentThread().getName(),instance);
});
cdl.countDown();
}
executorService.awaitTermination(5, TimeUnit.SECONDS);
executorService.shutdown();
}
日志信息
2021-03-04 17:05:39.718 INFO 15456 --- [pool-1-thread-7] org.example.singleton.SingletonTest : 线程 pool-1-thread-7 获取到的实例: org.example.singleton.Person@4d914f9d
2021-03-04 17:05:39.717 INFO 15456 --- [pool-1-thread-4] org.example.singleton.SingletonTest : 线程 pool-1-thread-4 获取到的实例: org.example.singleton.Person@4df33374
2021-03-04 17:05:39.718 INFO 15456 --- [pool-1-thread-3] org.example.singleton.SingletonTest : 线程 pool-1-thread-3 获取到的实例: org.example.singleton.Person@22230c
2021-03-04 17:05:39.718 INFO 15456 --- [pool-1-thread-8] org.example.singleton.SingletonTest : 线程 pool-1-thread-8 获取到的实例: org.example.singleton.Person@56e930d4
2021-03-04 17:05:39.717 INFO 15456 --- [ool-1-thread-10] org.example.singleton.SingletonTest : 线程 pool-1-thread-10 获取到的实例: org.example.singleton.Person@539d2805
2021-03-04 17:05:39.717 INFO 15456 --- [pool-1-thread-2] org.example.singleton.SingletonTest : 线程 pool-1-thread-2 获取到的实例: org.example.singleton.Person@5b1cf141
2021-03-04 17:05:39.719 INFO 15456 --- [pool-1-thread-9] org.example.singleton.SingletonTest : 线程 pool-1-thread-9 获取到的实例: org.example.singleton.Person@1244b7e5
2021-03-04 17:05:39.720 INFO 15456 --- [pool-1-thread-6] org.example.singleton.SingletonTest : 线程 pool-1-thread-6 获取到的实例: org.example.singleton.Person@1244b7e5
2021-03-04 17:05:39.717 INFO 15456 --- [pool-1-thread-5] org.example.singleton.SingletonTest : 线程 pool-1-thread-5 获取到的实例: org.example.singleton.Person@72896df6
2021-03-04 17:05:39.720 INFO 15456 --- [pool-1-thread-1] org.example.singleton.SingletonTest : 线程 pool-1-thread-1 获取到的实例: org.example.singleton.Person@1244b7e5
由上面日志信息可知,发现创建了多个Person实例对象。所以需要对其进行改造,改造代码如下:
public class ContainerSingleton {
// 定义容器
private static final ConcurrentHashMap<String,Person> CONTAINER = new ConcurrentHashMap<>();
public static Person getInstance(String name){
if (!CONTAINER.containsKey(name)){
synchronized (ContainerSingleton.class){
if (!CONTAINER.containsKey(name)){
Person person = new Person("befory");
CONTAINER.put(name,person);
}
}
}
return CONTAINER.get(name);
}
}
类似懒汉式单例中加强线程安全做法,加了检验机制,获取到的日志信息如下:
2021-03-04 17:12:36.987 INFO 15480 --- [pool-1-thread-8] org.example.singleton.SingletonTest : 线程 pool-1-thread-8 获取到的实例: org.example.singleton.Person@25fa0461
2021-03-04 17:12:36.987 INFO 15480 --- [pool-1-thread-1] org.example.singleton.SingletonTest : 线程 pool-1-thread-1 获取到的实例: org.example.singleton.Person@25fa0461
2021-03-04 17:12:36.989 INFO 15480 --- [pool-1-thread-5] org.example.singleton.SingletonTest : 线程 pool-1-thread-5 获取到的实例: org.example.singleton.Person@25fa0461
2021-03-04 17:12:36.987 INFO 15480 --- [pool-1-thread-9] org.example.singleton.SingletonTest : 线程 pool-1-thread-9 获取到的实例: org.example.singleton.Person@25fa0461
2021-03-04 17:12:36.990 INFO 15480 --- [pool-1-thread-6] org.example.singleton.SingletonTest : 线程 pool-1-thread-6 获取到的实例: org.example.singleton.Person@25fa0461
2021-03-04 17:12:36.990 INFO 15480 --- [ool-1-thread-10] org.example.singleton.SingletonTest : 线程 pool-1-thread-10 获取到的实例: org.example.singleton.Person@25fa0461
2021-03-04 17:12:36.988 INFO 15480 --- [pool-1-thread-3] org.example.singleton.SingletonTest : 线程 pool-1-thread-3 获取到的实例: org.example.singleton.Person@25fa0461
2021-03-04 17:12:36.990 INFO 15480 --- [pool-1-thread-4] org.example.singleton.SingletonTest : 线程 pool-1-thread-4 获取到的实例: org.example.singleton.Person@25fa0461
2021-03-04 17:12:36.991 INFO 15480 --- [pool-1-thread-2] org.example.singleton.SingletonTest : 线程 pool-1-thread-2 获取到的实例: org.example.singleton.Person@25fa0461
2021-03-04 17:12:36.987 INFO 15480 --- [pool-1-thread-7] org.example.singleton.SingletonTest : 线程 pool-1-thread-7 获取到的实例: org.example.singleton.Person@25fa0461
经过多次运行查看,从日志信息显示,获取实例地址均相同。
结论
各种方式的单例,都有各自的缺点,本文只是对线程安全上进行了对比与验证,得出的诸多结论。