单例模式
- 概述 : 是一种常用的软件设计模式.在它的核心结构中只包含一个被称为单例的特殊类.通过单例模式可以保证系统中一个类中只有一个实例.
- 要点
- 单例类只能有一个实例,
- 它必须自行创建这个实例
- 他必须自行向整个系统提供这个实例.
- 实现
- 单例模式的类只提供私有的构造函数
- 类定义中含有一个该类的静态私有对象
- 该类提供了一个静态的公有的函数用于创建或获取他本身的静态私有对象
- 代码实现
/**
* Created by looper on 2017/8/14.
*/
public class Singleton {
private static Singleton instance = null;
//保证外部不能通过构造方法实例化对象
private Singleton(){
}
//对外提供获取对象的接口
public static Singleton getInstance(){
if(instance == null){
return new Singleton();
}
return instance;
}
// 如果该对象被用于序列化,可以保证对象在序列化前后保持一致
public Object readResolve() {
return instance;
}
}
这是可以实现要求的写法,但是有一个问题,在多线程的情况下,不能保证 判断instance == null 时,instance就一定是null.怎么解决这个问题,
首先想到的
是使用
synchronized
关键字.
/**
* Created by looper on 2017/8/14.
*/
public class Singleton {
private static Singleton instance = null;
//保证外部不能通过构造方法实例化对象
private Singleton(){
}
//对外提供获取对象的接口
public static synchronized Singleton getInstance(){
if(instance == null){
return new Singleton();
}
return instance;
}
// 如果该对象被用于序列化,可以保证对象在序列化前后保持一致
public Object readResolve() {
return instance;
}
}
使用上边的写法每次调用getInstance方法,都会对对象上锁,这样在性能上有所下降.事实上,只有在第一次创建对象的时候是上锁就可以了.
优化代码如下.
饿汉模式
/**
* Created by looper on 2017/8/14.
*/
public class Singleton {
private static Singleton instance = null;
//保证外部不能通过构造方法实例化对象
private Singleton(){
}
//对外提供获取对象的接口
public static Singleton getInstance(){
if(instance == null){
synchronized (instance){
return new Singleton();
}
}
return instance;
}
// 如果该对象被用于序列化,可以保证对象在序列化前后保持一致
public Object readResolve() {
return instance;
}
}
懒汉式存在的问题:
- 懒汉式每次判断,当需要使用对象的时候才加载,会影响程序的速度.
- 在并发的情况下,懒汉式是不安全的,例如有两个线程:线程A.线程B.在同一时间调用getInstance()方法,如果线程A先进入判断(if)操作.然后线程B也进入并进行上锁控制,这样的结果是会有两个实例被创建.
饿汉式思想创建单例
/**
* Created by looper on 2017/8/14.
*/
public class Singleton {
//保证外部不能通过构造方法实例化对象
private Singleton(){
}
//使用内部类来维护单例
public static class SingletonFactory{
public static Singleton instance = new Singleton();
}
public Singleton getInsance(){
return SingletonFactory.instance;
}
// 如果该对象被用于序列化,可以保证对象在序列化前后保持一致
public Object readResolve() {
return getInsance();
}
}
通过这个方法,将单例的创建交给了内部类,内部类的静态方法保证了对象只能被实例一次.