在生活中我们经常会遇到这种情况:只能有一个对象存在。例如一个团队中只能有一个最高领导者、在windows系统中只能有一个资源管理器弹窗,这就需要使用单例模式来实现。
单例模式使我们在开发过程中最常用、最简单的设计模式,属于创建型模式,这种模式确保在整个程序中只能存在一个实例。
使用单例模式,增加了对象的复用率,减少了存储的压力,是一种最佳创建对象的方法。
单例模式的关键代码主要有三个点:
1、单例类只能有一个实例,可以通过同步或类加载原理实现;
2、单例类必须自己创建唯一的实例。所以需要将构造方法私有化;
3、单例类必须提供一个获取单例实例的方法。
本篇文章主要介绍6中常用单例。
1、懒汉式(线程不安全)
/**
* 懒汉式 线程不安全
* @author 樱桃肉丸子
*/
public class SinglePattern1 {
/**
* 将单例静态化、私有化
*/
private static SinglePattern1 instance;
/**
* 私有化构造方法
*/
private SinglePattern1(){}
/**
* 提供获取唯一实例方法
* @return
*/
public static SinglePattern1 getInstance(){
if(instance != null){
return instance;
}
return new SinglePattern1();
}
}
所谓懒汉式就是在需要用到实例的时候才会实例化单例对象。这种方式是最简单的单例模式,但当多个线程进行访问的时候,并没有做到真正的实例,所以在开发过程中不推荐该方法。
2、懒汉式(线程安全)
/**
* 懒汉式 线程安全
* @author 樱桃肉丸子
*/
public class SinglePattern2 {
/**
* 单例私有化、静态化
*/
private static SinglePattern2 instance;
/**
* 私有化构造方法
*/
private SinglePattern2(){}
/**
* 提供获取唯一实例方法 同时加锁
* @return
*/
public static synchronized SinglePattern2 getInstance(){
if(instance == null){
return new SinglePattern2();
}
return instance;
}
}
这种方法是懒汉式的另一种实现,通过同步关键字来修饰保证线程安全。但加锁会影响到性能,所以在并发量较大的情况下不推荐使用该方法。
3、饿汉式
/**
* 饿汉式
* @author 樱桃肉丸子
*/
public class SinglePattern3 {
/**
* 私有化、静态化实例
*/
private static SinglePattern3 instance = new SinglePattern3();
/**
* 私有化构造方法
*/
private SinglePattern3 (){}
/**
* 提供获取唯一实例方法
* @return
*/
public static SinglePattern3 getInstance(){
return instance;
}
}
所谓饿汉式就是在类加载的时候就创建了实例,同时也是线程安全的。与上一种方式不同的是,这种方法通过类加载原理实现整个程序中只有这一个实例,展开说就是静态变量只会在类加载的时候进行声明和实例化。但这种方式也存在缺点,即在类加载的时候就会实例化但该对象并不会用到,所以占用了部分内存。在开发过程中,最经常用到的就是这种方法。
4、双检索式
/**
* 双检索式
* @author 樱桃肉丸子
*/
public class SinglePattern4 {
/**
* 单例静态化,同时用volatile修饰保证所有线程读取的是一个实例
*/
private volatile static SinglePattern4 singleton;
/**
* 私有化构造方法
*/
private SinglePattern4 (){}
/**
* 提供获取唯一实例方法
* @return
*/
public static SinglePattern4 getInstance() {
if (singleton == null) {
synchronized (SinglePattern4.class) {
if (singleton == null) {
singleton = new SinglePattern4();
}
}
}
return singleton;
}
}
双检索式是第二种和第三种的结合体,在线程安全的情况下依然保持着高性能。
5、静态内部类式
/**
* 静态内部类式
* @author 樱桃肉丸子
*/
public class SinglePattern5 {
/**
* 定义私有静态内部类
*/
private static class SingletonHolder {
private static final SinglePattern5 INSTANCE = new SinglePattern5();
}
/**
* 私有化构造方法
*/
private SinglePattern5 (){}
/**
* 提供获取唯一实例方法
* @return
*/
public static final SinglePattern5 getInstance() {
return SingletonHolder.INSTANCE;
}
}
这种方式使用静态内部类来实现,也是使用类加载的原理实现的线程安全,但与第三种不同的是,这种方式在类加载的时候并不会立刻创建单例,属于懒加载。所以这种方式相对于第三种方式来讲更合理。
6、枚举
/**
* 枚举
* @author 樱桃肉丸子
*/
public enum SinglePattern6 {
INSTANCE;
public void whateverMethod() {
}
}
这是实现单例模式的最佳方法,支持序列化,但这种模式还没有完全被普及,在工作过程中其实很少用到。
总结:
一般情况下不推荐使用懒汉式单例,推荐使用饿汉式单例。如果有明确的懒加载需求,可以使用静态内部类方式实现,若涉及到序列化等问题可以使用枚举方式,其他特殊需求可以考虑双检索方式。
转载于:https://blog.51cto.com/13593129/2287034