1、前言
面试时,经常会问到单例模式。
单例模式的两种方式:
- 饿汉式,就是在类初始化的时候,创建对象。这种方式没有考虑线程安全问题,在多线程下,可能同时存在多个对象。
- 懒汉式,懒汉式是在第一次使用时才创建对象,在多线程环境中要考虑线程安全问题。
2、怎么区分饿汉和懒汉模式
饿汉: 饿了,饥不择食,系统一运行就创建对象,不考虑太多的问题(如线程安全问题)。
懒汉: 就是懒,就是不想创建对象,即使运行创建对象,每走一步都要找各种理由、说一大堆的问题,要考虑什么多线程、安全,对象重复等问题。总之一句话:懒,就是不想创建。
3、 饿汉
系统一运行就创建对象,不考虑太多的问题,所以可能会被创建多次,存在多个对象。
public class Singleton{
//类加载时就初始化
private static final Singleton instance = new Singleton();
private Singleton(){}
public static Singleton getInstance(){
return instance;
}
}
比较喜欢的方式:饿汉式,不用考虑线程安全问题。
4、懒汉 (双重检查 Double Check Lock)
就是不想创建对象。做什么都要找理由 ( 即使运行创建对象,也要考虑多线程、安全,对象重复等问题)。
总之一句话:懒!
public class Singleton {
// 必须声明 volatile,在多线程中instance被修改后能立即更新到主内存中
// 如果不声明,就不是线程安全的
private volatile static Singleton instance = null;
private Singleton (){}
public static Singleton getSingleton() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
ReentrantLock 实现 :
import java.util.concurrent.locks.ReentrantLock;
public class Singleton2 {
// 必须声明 volatile,在多线程中instance被修改后能立即更新到主内存中
// 如果不声明,就不是线程安全的
private volatile static Singleton2 instance = null;
private static ReentrantLock lock = new ReentrantLock();
private Singleton2() {
}
public static Singleton2 getSingleton() {
if (instance == null) {
lock.lock();
try {
if (instance == null) {
instance = new Singleton2();
}
} finally {
lock.unlock();
}
}
return instance;
}
}
注意:
必须声明 volatile
,在多线程中instance被修改后能立即更新到主内存中。
5、饿汉模式在JDK中的应用(Runtime)
6、相关文章
别再用懒汉模式了——从JVM的角度看单例模式: https://blog.csdn.net/qq_33745799/article/details/88737999