单例模式保证了一个应用中有且只有一个实例存在。
单例类必须提供一个全局的访问来获取类的实例。
单例模式用来日志,驱动对象,缓存和线程池。
单例设计模式也用在其他设计模式,例如抽象工厂,建造者,原型,门面等设计模式
JDK中的单例模式:java.lang.Runtime;
单例模式的共同概念
- 私有构造方法限制从其他类创建对象
- 私有静态变量与该类的实例相同
- 定义一个公有静态方法,返回该类的对象
实现类型:
- 饿汉模式
- 静态代码块
- 懒汉模式
- 线程安全的单例
- 线程安全的双重校验锁
- 内部内实现
- 枚举实现
1. 饿汉模式
饿汉模式就是当类加载时就创建该类的实例,这是创建单例类最容易的方法。
弊端是,创建了该实例但是客户端程序如果不使用这个实例,造成资源浪费
public class EagerSingleton {
//实例化
private static EagerSingleton instance = new EagerSingleton();
//私有化构造方法
private EagerSingleton() {
}
public static EagerSingleton getInstance() {
return instance;
}
}
2. 静态代码块(饿汉模式)
饿汉模式的变体,可以进行异常处理,优缺点和饿汉模式一样
public class StaticSingleton {
private static StaticSingleton instance;
//添加了异常处理
static {
try {
instance = new StaticSingleton();
}catch (Exception e) {
throw new RuntimeException("静态代码块初始化失败");
}
}
public static StaticSingleton getInstance() {
return instance;
}
}
懒汉模式
相比于之前两种方法,懒汉模式就是当需要用的时候再来创建对象
线程不安全的写法,单线程可用
public class LazySingleton {
private static LazySingleton instance = null;
private LazySingleton() {
}
public static LazySingleton getInstance() {
if(instance == null) {
instance = new LazySingleton();
}
return instance;
}
}
线程安全的单例(不推荐)
加了同步关键字,但是多个线程获得实例的时候,都要进行同步,效率太低了。
public class SafeSingleton {
private static SafeSingleton instance = null;
private SafeSingleton() {
}
//同步关键字synchronized
public static synchronized SafeSingleton getInstance() {
if(instance == null) {
instance = new SafeSingleton();
}
return instance;
}
}
线程安全的双重校验锁
public class SafeSingleton {
private static SafeSingleton instance = null;
private SafeSingleton() {
}
public static SafeSingleton getInstance() {
//此层的控制允许第一线程进入访问。
if(instance == null) {
synchronized(StaticSingleton.class) {
//此处校验单例是否已经被创建,确定只有一个实例存在。
if(instance == null) {
instance = new SafeSingleton();
}
}
}
return instance;
}
}
内部类实现单例
这种方式既保证了只有一个实例,又可以在需要的时候创建。线程安全,效率高
public class InterSingleton {
private InterSingleton() {
}
//内部类
private static class SingletonHolder{
private static InterSingleton instance = new InterSingleton();
}
public static InterSingleton getInstance() {
return SingletonHolder.instance;
}
}
枚举实现
写法简单,线程安全,还能反序列化重新创建对象。
public enum EnumSingleton {
instance;
private EnumSingleton() {
}
public void method() {
}
}
//访问
EnumSingleton.instance.method();
总结
实际常用的是饿汉模式,懒汉模式双重校验锁,内部类实现,枚举实现。
最安全的写法是枚举实现(在反射机制中都可以保证唯一性)