面试题:手写单例模式
单例模式是最常用的设计模式之一,单代表唯一,例代表实例。
单例设计模式,即某个类在整个系统中只能有一个实例,对象可被获取和使用的代码模式。
例如:代表 JVM 运行环境的 Runtime 类。
可参考我的博客《设计模式-单例模式》
单例模式的要点:
- 某个类只能有一个实例
- 构造器私有化
- 类必须自行创建整个实例
- 含有一个该类的静态变量来保存这个唯一的实例
- 类必须自行向整个系统提供这个实例
- 对外提供获取该实例对象的方式
单例模式可以分为饿汉式和懒汉式两大类。
饿汉式:直接创建对象,不存在线程安全问题
- 1、直接实例化饿汉式(简洁直观)
- 2、静态代码块饿汉式(适合复杂实例化)
- 3、枚举式(最简洁)
懒汉式:延迟创建对象
- 4、线程不安全式(适用于单线程)
- 5、双重校验式,线程安全(适用于多线程)
- 6、静态内部类式(适用于多线程)
第一种形式的示例代码:
public class Singleton1 {
public final static Singleton1 singleton = new Singleton1();
private Singleton1() {
}
}
第二种形式的示例代码:
适合复杂的初始化代码,如从配置文件中读取配置。
public class Singleton2 {
public final static Singleton2 INSTANCE;
static {
INSTANCE = new Singleton2();
}
private Singleton2() {
}
}
第三种形式的示例代码:
利用枚举类的特点,编译时创建单例对象。
public enum Singleton3 {
INSTANCE
}
第四种形式的示例代码:
单线程下安全,进入 if 语句的线程可能不止一个。
public class Singleton4 {
private static Singleton4 INSTANCE;
private Singleton4() {
}
public static Singleton4 getInstance() {
if (INSTANCE == null) {
// 线程睡眠,便于多线程环境下测试
// try {
// Thread.sleep(100);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
INSTANCE = new Singleton4();
}
return INSTANCE;
}
}
第五种形式的示例代码:
增加线程同步关键字,来避免上面单线程中创建多个对象的问题。
public class Singleton5 {
private static Singleton5 INSTANCE;
private Singleton5() {
}
public static Singleton5 getInstance() {
// 缩小 synchronized 关键字的作用范围
synchronized (Singleton4.class) {
if (INSTANCE == null) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
INSTANCE = new Singleton5();
}
}
return INSTANCE;
}
}
优化版本:
使用双重校验,提高性能。
public class Singleton5 {
private static Singleton5 INSTANCE;
private Singleton5() {
}
public static Singleton5 getInstance() {
// 第一次创建单例对象时需要保护,创建完成后就只需要判断一下就行了
if (INSTANCE == null) {
synchronized (Singleton4.class) {
if (INSTANCE == null) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
INSTANCE = new Singleton5();
}
}
}
return INSTANCE;
}
}
第六种形式的示例代码:
在内部类被加载和初始化时,创建单列对象,且只创建一次。
public class Singleton6 {
private Singleton6() {
}
static class Inner {
private static final Singleton6 INSTANCE = new Singleton6();
}
public static Singleton6 getInstance() {
return Inner.INSTANCE;
}
}
六种单例方式的测试代码:
public class TestSingleton {
@Test
public void testSingle01() throws ExecutionException, InterruptedException {
// 多线程测试
Callable<Singleton1> call = new Callable<Singleton1>() {
@Override
public Singleton1 call() throws Exception {
return Singleton1.INSTANCE;
}
};
ExecutorService executorService = Executors.newFixedThreadPool(2);
Future<Singleton1> f1 = executorService.submit(call);
Future<Singleton1> f2 = executorService.submit(call);
Singleton1 s1 = f1.get();
Singleton1 s2 = f2.get();
System.out.println(s1 == s2); // false,创建了多个单例对象
System.out.println(s1);
System.out.println(s2);
executorService.shutdown();
}
@Test
public void testSingle02() throws ExecutionException, InterruptedException {
// 多线程测试
Callable<Singleton2> call = new Callable<Singleton2>() {
@Override
public Singleton2 call() throws Exception {
return Singleton2.INSTANCE;
}
};
ExecutorService executorService = Executors.newFixedThreadPool(2);
Future<Singleton2> f1 = executorService.submit(call);
Future<Singleton2> f2 = executorService.submit(call);
Singleton2 s1 = f1.get();
Singleton2 s2 = f2.get();
System.out.println(s1 == s2); // false,创建了多个单例对象
System.out.println(s1);
System.out.println(s2);
executorService.shutdown();
}
@Test
public void testSingle03() throws ExecutionException, InterruptedException {
// 多线程测试
Callable<Singleton3> call = new Callable<Singleton3>() {
@Override
public Singleton3 call() throws Exception {
return Singleton3.INSTANCE;
}
};
ExecutorService executorService = Executors.newFixedThreadPool(2);
Future<Singleton3> f1 = executorService.submit(call);
Future<Singleton3> f2 = executorService.submit(call);
Singleton3 s1 = f1.get();
Singleton3 s2 = f2.get();
System.out.println(s1 == s2); // false,创建了多个单例对象
System.out.println(s1);
System.out.println(s2);
executorService.shutdown();
}
@Test
public void testSingle041() {
// 单线程测试
Singleton4 s1 = Singleton4.getInstance();
Singleton4 s2 = Singleton4.getInstance();
System.out.println(s1 == s2); // true,只创建了一个单例对象
System.out.println(s1);
System.out.println(s2);
}
@Test
public void testSingle042() throws ExecutionException, InterruptedException {
// 多线程测试
Callable<Singleton4> call = new Callable<Singleton4>() {
@Override
public Singleton4 call() throws Exception {
return Singleton4.getInstance();
}
};
ExecutorService executorService = Executors.newFixedThreadPool(2);
Future<Singleton4> f1 = executorService.submit(call);
Future<Singleton4> f2 = executorService.submit(call);
Singleton4 s1 = f1.get();
Singleton4 s2 = f2.get();
System.out.println(s1 == s2); // false,创建了多个单例对象
System.out.println(s1);
System.out.println(s2);
executorService.shutdown();
}
@Test
public void testSingle05() throws ExecutionException, InterruptedException {
// 多线程测试
Callable<Singleton5> call = new Callable<Singleton5>() {
@Override
public Singleton5 call() throws Exception {
return Singleton5.getInstance();
}
};
ExecutorService executorService = Executors.newFixedThreadPool(2);
Future<Singleton5> f1 = executorService.submit(call);
Future<Singleton5> f2 = executorService.submit(call);
Singleton5 s1 = f1.get();
Singleton5 s2 = f2.get();
System.out.println(s1 == s2); // true,只创建了一个单例对象
System.out.println(s1);
System.out.println(s2);
executorService.shutdown();
}
@Test
public void testSingle06() throws ExecutionException, InterruptedException {
// 多线程测试
Callable<Singleton6> call = new Callable<Singleton6>() {
@Override
public Singleton6 call() throws Exception {
return Singleton6.getInstance();
}
};
ExecutorService executorService = Executors.newFixedThreadPool(2);
Future<Singleton6> f1 = executorService.submit(call);
Future<Singleton6> f2 = executorService.submit(call);
Singleton6 s1 = f1.get();
Singleton6 s2 = f2.get();
System.out.println(s1 == s2); // true,只创建了一个单例对象
System.out.println(s1);
System.out.println(s2);
executorService.shutdown();
}
}
点击查看更多内容
为 TA 点赞
评论
共同学习,写下你的评论
评论加载中...
作者其他优质文章
正在加载中
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦