一个类只有一个对象实例,并且提供全局的访问
常见的几种方法
/**
* 饿汉式 线程安全 在类装载就完成实例化,没达到懒加载(使用较多)
*/
class Singleton1 {
private static Singleton1 instance = new Singleton1();
private Singleton1() {
}
public static Singleton1 getInstance() {
return instance;
}
}
// 懒汉式 解决了懒加载 只有加锁才是线程安全,效率太低 不讨论
/**
* 双重检测 (双重检查锁) 解决线程安全 懒加载 效率
*/
class Singleton2 {
//volatile 保证修改,其他线程可见 防止指令重排(轻量级synchronized)
private static volatile Singleton2 instance;
private Singleton2() {
}
public static Singleton2 getInstance() {
if (instance == null) {
synchronized (Singleton2.class) {
if (instance == null) {
instance = new Singleton2();
}
}
}
return instance;
}
}
/**
* 静态内部类 Singleton3在装载不会立即实例化 而是在需要实例化时 调用getInstance
* 才会装载SingletonHolder 从而完成实例化 (推荐使用)
*/
class Singleton3 {
private static class SingletonHolder {
private static final Singleton3 INSTANCE = new Singleton3();
}
private Singleton3 (){}
public static Singleton3 getInstance() {
return SingletonHolder.INSTANCE;
}
}
/**
* 枚举 这种实现方式还没有被广泛采用,但这是实现单例模式的最佳方法。它更简洁,自动支持序列化机制,绝对防止多次实例化。
*/
enum Singleton5 {
INSTANCE;
public void whateverMethod() {
}
}
实例:
- Hibernate的sessionFactory
- 创建HttpClient(饿汉式)
@Slf4j
public class HttpClientUtil {
private static CloseableHttpClient httpClient = HttpClients.createDefault();
private HttpClientUtil() {
}
/**
* 创建httpclient
*/
public static CloseableHttpClient getInstance() {
return httpClient;
}
/**
* 释放httpclient
*/
public static void release() throws IOException {
if (httpClient != null) {
httpClient.close();
log.info("释放HttpClient");
}
}
}
-
JDK源码 Runtime(饿汉模式)
结论:
不建议使用懒汉方式 建议使用饿汉方式
只有在懒加载 推荐使用静态内部类 也可使用双重锁校验
如果涉及到反序列化创建对象时 可以使用枚举方式
使用场景
-
频繁创建销毁的对象
- 创建对象消耗过多资源,但又经常访问的对象
- 工具类对象