单例模式
单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
UML图
常见应用场景
- Windows的任务管理器就是典型的单例模式
- windows的回收站
- web网站的计数器
- Spring种,每个Bean默认就是单例模式
- SpringMvc/Struts框架,控制器也是单例模式
- 数据库连接池
常见实现方法
主要
- 饿汉式(线程安全,调用效率高。初始化时立即加载,天然的线程安全)
- 懒汉式(线程安全,调用效率不高。第一次使用时加载,即可以延时加载)
其他
- 双重检测锁式(由于编译器优化原因和JVM底层内部模式原因偶尔会出现问题,不介意使用)
- 静态内部类式(线程安全,调用效率高。可以延时加载)
- 枚举单例(线程安全,调用效率高,不能延时加载)
Java编码
饿汉式
/**
* 饿汉式 单例模式
* 线程安全,调用效率高。初始化时立即加载,天然的线程安全
* @author H
*
*/
public class Singleton {
// 类初始化时,立即加载这个对象,没有延时加载的优势。加载类时,天然的线程安全
private static Singleton singleton = new Singleton();
private Singleton() {}
//无需加上 synchronized
public static Singleton getInstance() {
return singleton;
}
}
懒汉式
/**
* 懒汉式 单例模式
* 线程安全,第一次使用时加载,即可以延时加载
* 资源利用率高,但是每次调用都要同步,并发效率较低
* @author H
*
*/
public class Singleton {
// 类初始化时,立即加载这个对象,没有延时加载的优势。加载类时,天然的线程安全
private static Singleton singleton ;
private Singleton() {}
//需要加上synchronized关键字,并发效率较低
public synchronized static Singleton getInstance() {
if(singleton == null) {
singleton = new Singleton();
}
return singleton;
}
}
双重检测锁式
由于编译器优化原因和JVM底层内部模式原因偶尔会出现问题,不介意使用
/**
* 双重检测锁式(double check)
* @author H
*
*/
public class Singleton {
private static Singleton singleton ;
private Singleton() {}
/**
* 将同步放入if内部,提高了执行的效率,不必每次获取对象都需要同步,只有第一次创建对象时需要同步
* 创建后就没有必要了
*/
public static Singleton getInstance() {
if(singleton == null) {
Singleton s ;
synchronized (Singleton.class) {
s = singleton;
if(s == null) {
synchronized (Singleton.class) {
if(s == null) {
s = new Singleton();
}
}
singleton = s;
}
}
}
return singleton;
}
}
双重检测锁式,也可以使用volatile关键字实现。
public class Singleton {
private volatile static Singleton singleton;
private Singleton() {}
public static Singleton getInstance() {
if (singleton== null) {
synchronized (Singleton.class) {
if (singleton== null) {
singleton= new Singleton();
}
}
}
return singleton;
}
}
静态内部类式
/**
* 静态内部类实现方式
* 线程安全,调用效率高,实现延时加载
* @author H
*
*/
public class Singleton {
private Singleton(){}
//调用getInstance时才初始化静态内部类SingletonHolder从而创建Singleton对象
//同饿汉式一样,天然的线程安全
private static class SingletonHolder{
private static Singleton singleton = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.singleton;
}
}
枚举
枚举本身就是一个单例,并且在枚举中也可以声明一些行为方法。所以我们也可以直接使用枚举来实现单例模式
/**
* 枚举
* 线程安全,调用效率高,不能延时加载
* @author H
*
*/
public enum Singleton {
INSTANCE;
}
总结
在各种单例模式的实现中,个人比较推荐内部静态类的方式。
当然,如果不需要延时加载的话,采用饿汉式的直接初始化的效果更好。