0%

实现SingleTton模式

实现SingleTton模式

一、题目

设计一个类,我们只能生成该类的一个示例。

只能生成一个实例的是为了实现Singleton(单例)模式的类型,设计模式在面向对象程序设计中起着举足轻重的作用,在面试过程中公司都喜欢问一些与设计模式相关的问题。在常用的设计模式中,Singleton是唯一一个能够用几十行代码完整实现的模式。因此,写一个Singleton的类型是一个很常见的面试题。

二、参考解法

1、懒汉式——线程安全

1
2
3
4
5
6
7
8
9
10
11
public class Singleton{
private class Singleton(){}//私有构造函数,即对外隐藏构造函数

private static class Singeleton instance = null;

public static Singleton getInstance(){
if(instance == null)//仅当instance 为null时才创建一个实例,以避免重复创建。
instance = new Singleton();
return instance
}
}

该解法在单线程的时候共工作正常,但在多线程的情况下不适用。设想如果两个线程同时运行到判断instance是否为null的if语句,并且instance的确没有创建时,那么两个线程都会创建一个实例,此时就不满足单例模式的要求。

2、懒汉式——线程安全

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Singleton{
private Singleton(){}//私有构造函数,即对外隐藏构造函数

private static Singleton instance = null;

private static Object object = new Object();

public static Singleton getInstance(){
synchronized(object){//每次只允许一个线程进入代码块,因此不会出现多线程下创建同一个实例的情况
if(instance == null)
instance = new Singleton();
}
return instance;
}
}

该解法在多线程环境下使用正常,但是并不完美。在执行过程中,每次都需通过getInstance()得到Singleton实例,并且在此方法中都会加上同步锁,而加锁是一个非常耗时的操作,在没有必要的时候应尽量避免

3、双重校验锁——线程安全

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Singleton{
private Singleton(){}//私有构造函数,即对外隐藏构造函数

private volatile static Singleton instance = null;

private static Object object = new Object();

public static Singleton getInstance(){
if(instance == null){
synchronized(object){//每次只允许一个线程进入代码块,因此不会出现多线程下创建同一个实例的情况
if(instance == null)
instance = new Singleton();
}
}

return instance;
}
}

该解法只有当instancenull即没有创建时,需要加锁操作。当instance已经创建出来之后,则无需加锁。相比于解法二大大提高了效率,但是代码实现起来比较复杂,容易出错。

instance 采用 volatile 关键字修饰也是很有必要的。instance = new Singleton(); 这段代码其实是分为三步执行。volatile禁止指令重排。

  1. 分配内存空间
  2. 初始化对象
  3. 将 uniqueInstance 指向分配的内存地址

4、饿汉式——线程安全

1
2
3
4
5
6
7
8
9
public class Singleton{
private Singleton(){}//私有构造函数,即对外隐藏构造函数

private static Singleton instance = new Singleton();

public static Singleton getInstance(){
return instance;
}
}

利用静态属性、静态代码块的性质,确保只在加载时调用一次。该段代码非常简洁地实现了功能,但是调用静态构造函数地时机并不是由程序员掌控,而是由JVM运行时发现第一次使用一个类型的时候自动调用该类型的静态构造函数。即实例instance并不是第一次调用属性Singleton.getInstance时创建,而是在第一次用到Singleton时创建。(降低内存的使用效率)

5、静态内部类——按需创建

1
2
3
4
5
6
7
8
9
10
public class Singleton{
private Singleton(){}//私有构造函数,即对外隐藏构造函数

public static Singleton getInstance(){
return Nested.instance;
}
static class Nested{//外部类加载时,静态内部类不会同时加载,而是在调用静态内部类(静态域、静态方法、构造函数)时加载。
static Singleton instance = new Singleton();
}
}

6、枚举

1
2
3
public enum Singleton {
uniqueInstance;
}

单例模式的最佳实践,它实现简单,并且在面对复杂的序列化或者反射攻击的时候,能够防止实例化多次。

-------------本文结束感谢您的阅读-------------
坚持原创技术分享,您的支持将鼓励我继续创作!

欢迎关注我的其它发布渠道