一.单例模式简介
单例:作为对象的创建模式,单例模式确保某一个类只有一个实例,而且自动实例化并向整个系统提供这个实例。这个类称为单例类。
单例模式的结构:
- 单例类只能有一个实例
- 单例类必须自己创建自己的唯一实例
- 例类必须给所有其他对象提供这一实例
二.饿汉式单例
/*
* 饥饿式单例类
*/
public class SingletionDemo1 {
private static SingletionDemo1 instance=new SingletionDemo1();
/**
* 私有构造
*/
private SingletionDemo1() {
}
/*
* 静态工厂方法
*/
public static SingletionDemo1 getInstance() {
return instance;
}
}
上面的例子中,在这个类被加载时,静态变量instance会被初始化,此时类的私有构造子会被调用。这时候,单例类的唯一实例就被创建出来了
饿汉式其实是一种比较形象的称谓,既然饿,那么在创建对象实例的时候就比较着急,饿了嘛,于是在装载类的时间就创建实例
private static SingletionDemo1 instance=new SingletionDemo1();
饿汉式是典型的空间换时间,当类装载的时候就会创建类的实例,不管你用不用,先创建出来,然后每次调用的时候,就不需要再判断,节省了运行时间
变种饿汉式
public class Singleton {
private static Singleton instance;
static {
instance=new Singleton();
}
public Singleton() {
// TODO Auto-generated constructor stub
}
public static Singleton getInstance() {
return instance;
}
}
三.懒汉式单例
/*
* 饿汉式单例类
*/
public class SingletionDemo2 {
private static SingletionDemo2 instance=null;
/*
* 私有默认构造子
*/
private SingletionDemo2() {
}
/*
* 静态工厂方法
*/
public static synchronized SingletionDemo2 getInstance() {
if(instance==null) {
instance=new SingletionDemo2();
}
return instance;
}
}
- 上面的懒汉式单例类实现里对静态工厂方法使用了同步化,以处理多线程环境
- 懒汉式其实是一种比较形象的称谓,既然懒,那么在创建对象实例的时候就不着急。会一直等到马上要使用对象实例的时候才会创建,懒人嘛,总是推脱不开的时候才会真正去执行工作,因此在装载对象的时候不创建对象实例
private static SingletionDemo2 instance=null;
- 懒汉式是典型的时间换空间,就是每次获取实例都会进行判断,看是否需要创建实例,浪费判断的时间。当然,如果一直没有人使用的话,那就不会创建实例,则节约内存空间
- 由于懒汉式的实现是线程安全的,这样会降低整个访问的速度,而且每次都要判断。那么有没有更好的方式实现呢?
四.双重检查锁
双重检查锁可以实现线程安全,又能够使性能不受很大的影响。或许有很多人想问为什么用使用双重检查锁。其实这个需要解释一下了。
比如现在有两个线程来访问,都访问到了第一个if(instance==null)后面了,但因为后面是同步块,只能一个线程进入,另一个等待在同步块,访问后实例化了一个对象,退出同步块后,另一个等待的线程进入同步代码块,但因为instance已经被实例化了,所以直接退出同步代码块,直接返回instance
在JDK1.5之后,双重检查锁定才能够正常达到单例效果。
public class Singleton {
private volatile static Singleton instance=null;
public Singleton() {
}
public Singleton getInstance() {
//先检查对象是否存在,如果不存在才进入下面的同步块
if(instance==null) {
//同步块,线程安全的创建
synchronized(Singleton.class) {
//若实例还是为空,那就创建
if(instance==null) {
instance=new Singleton();
}
}
}
return instance;
}
}
五.静态内部类
public class Singleton {//这个不同于饿汉式的,在类的加载中,对象就会被实例化,只要调用getInstance方法才会加载类SingletonHandler,让instance对象实例化,这种方式实现了线程安全,在一定程度上也可以有很好的性能。
private static class SingletonHandler{
private static final Singleton instance=new Singleton();
}
private Singleton() {
// TODO Auto-generated constructor stub
}
public static final Singleton getInstance() {
return SingletonHandler.instance;
}
}
六.枚举
public enum Singleton {
//Singleton的一个实例
instance;
//功能的操作
public void waterSingleton() {
}
}