设计模式——单例模式
单例模式:
- 单例类只能有一个实例
- 单例类必须自己创建自己的唯一实例
- 单例类必须给其他所有对象提供这一实例
单例模式的七种实现形式:
1. 饿汉式
- 过程特点:先进行类的初始化,在程序执行的时候变量已经是初始化之后的了;
- 线程安全:饿汉式是线程安全的单例模式,因为从代码来看,进入程序后首先就初始化了static变量,之后调用getInstance()的时候,事实上s1是已经被初始化之后的了,所以它不论几个线程都不会改变;
- 懒加载:懒加载就是在要使用的时候才去初始化,很明显,饿汉式没有懒加载的过程;
public class Singleton1 {
private static final Singleton1 s1 = new Singleton1();
private Singleton1(){}
public static Singleton1 getInstance(){
return s1;
}
}
2. 懒汉式
懒汉式和饿汉式相比的区别就是懒汉式创建了延迟对象同时饿汉式的实例对象是被修饰为final类型。
- 优点:懒汉式的好处是显而易见的,它尽最大可能节省了内存空间。
- 缺点:在多线程编程中,使用懒汉式可能会造成类的对象在内存中不唯一,虽然通过修改代码可以改正这些问题,但是效率却又降低了。
- 特点:线程不安全,实现了实例懒加载策略。
public class Singleton2 {
private static Singleton2 s2 = null;
private Singleton2(){}
public Singleton2 getInstance(){
if(s2 == null){
s2 = new Singleton2();
}
return s2;
}
}
3. 全局锁式
- 特点:线程安全,且实现了懒加载策略,但是线程同步时效率不高。
public class Singleton3 {
private static Singleton3 s3;
private Singleton3(){}
public static synchronized Singleton3 getInstance(){
if(s3 == null)
s3 = new Singleton3();
return s3;
}
}
4. 静态代码块式
- 特点:线程安全,类主动加载时才初始化实例,实现了懒加载策略,且线程安全。而且由于没有synchronized关键字重锁,所以会相对提高效率,所以静态代码块实现单例模式也是很常用的。
public class Singleton4 {
private final static Singleton4 s4;
private Singleton4() {}
static{
s4 = new Singleton4();
}
public static Singleton4 getInstance(){
return s4;
}
}
5. 双重校验锁式
- 特点:线程安全,且实现了懒加载策略,同时保证了线程同步时的效率。但是volatile强制当前线程每次读操作进行时,保证所有其他的线程的写操作已完成。volatile使得JVM内部的编译器舍弃了编译时优化,对于性能有一定的影响。
public class Singleton5 {
private static volatile Singleton5 s5;
private Singleton5(){}
public static Singleton5 getInstance(){
if(s5 == null){
synchronized (Singleton5.class) {
if (s5 == null) {
s5 = new Singleton5();
}
}
}
return s5;
}
}
6. 静态内部类式
- 特点:线程安全,不存在线程同步问题,且单例对象在程序第一次 getInstance() 时主动加载 SingletonHolder 和其 静态成员 INSTANCE,因而实现了懒加载策略。
public class Singleton6 {
private Singleton6(){}
private static class Single{
private static final Singleton6 SINGLETON_6 = new Singleton6();
}
public static Singleton6 getInstance(){
return Single.SINGLETON_6;
}
}
7.枚举式
- 特点:线程安全,不存在线程同步问题,且单例对象在枚举类型 INSTANCE,第一次引用时通过枚举的 构造函数 初始化,因而实现了懒加载策略。这种方式是Effective Java作者 Josh Bloch 提倡的方式,它不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象,可谓是很坚强的壁垒啊。不过,JDK 1.5中才加入enum特性 。
public class Singleton7 {
private Singleton7() {}
enum SingletonEnum {
INSTANCE;
private final Singleton7 s7;
private SingletonEnum() {
s7 = new Singleton7();
}
}
public static Singleton7 getInstance() {
return SingletonEnum.INSTANCE.s7;
}
}