单例模式(Singleton)是一种常用的创建型软件设计模式。在应用这个模式时,单例对象的类必须保证只有一个实例存在。许多时候整个系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为。比如在某个服务器程序中,该服务器的配置信息存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象再通过这个单例对象获取这些配置信息。这种方式简化了在复杂环境下的配置管理。
实现方式 | 例子 |
---|---|
饿汉式 | SingletonHungry、SingletonHungryVariant |
懒汉式 | SingletonLazy、SingletonLazySynchronizedMethod、SingletonLazySynchronizedBlock |
双重检查 | SingletonDoubleCheck、SingletonDoubleCheckWithVolatile |
枚举 | SingletonEnumHungry、SingletonEnumLazy |
静态内部类 | SingletonStaticInnerClass |
public class SingletonHungry {
private static SingletonHungry singleton = new SingletonHungry();
private SingletonHungry() {}
public static SingletonHungry getInstance() {
return singleton;
}
}
public class SingletonHungryVariant {
private static SingletonHungryVariant singleton;
static {
singleton = new SingletonHungryVariant();
}
private SingletonHungryVariant(){}
public static SingletonHungryVariant getInstance(){
return singleton;
}
}
public class SingletonLazy {
private static SingletonLazy singleton;
private SingletonLazy() {}
public static SingletonLazy getInstance() {
if (null == singleton) {
singleton = new SingletonLazy();
}
return singleton;
}
}
public class SingletonLazySynchronizedMethod {
private static SingletonLazySynchronizedMethod singleton;
private SingletonLazySynchronizedMethod() {}
public static synchronized SingletonLazySynchronizedMethod getInstance() {
if (singleton == null) {
singleton = new SingletonLazySynchronizedMethod();
}
return singleton;
}
}
public class SingletonLazySynchronizedBlock {
private static SingletonLazySynchronizedBlock singleton;
private SingletonLazySynchronizedBlock() {}
public static SingletonLazySynchronizedBlock getInstance() {
if (singleton == null) {
synchronized (SingletonLazySynchronizedBlock.class) {
singleton = new SingletonLazySynchronizedBlock();
}
}
return singleton;
}
}
public class SingletonDoubleCheck {
private static SingletonDoubleCheck singleton;
private SingletonDoubleCheck(){}
private static SingletonDoubleCheck getInstance(){
if (singleton == null){//一
synchronized (SingletonDoubleCheck.class){
if (singleton == null){
singleton = new SingletonDoubleCheck();//二
}
}
}
return singleton;
}
}
说明:
Java创建一个对象,在Java虚拟机上会进行以下三步操作
1、给singleton分配内存
2、调用构造器方法,执行初始化
3、将对象引用赋值给变量
Java实例化一个对象的操作(new)不是原子性的,存在指令重排序的问题,上面三个操作的顺序可能是123,也可能是132(步骤1不会重排序,因为23依赖1的结果),当指令顺序为132时,就可能出现对象空指针异常,表格示意如下:
时间 | 线程a | 线程b |
---|---|---|
t1 | 分配内存 | |
t2 | 变量赋值 | |
t3 | 判断对象是否为null | |
t4 | 由于对象变量已赋值,故不为null,访问并修改对象 | |
t5 | 初始化对象 |
public class SingletonDoubleCheckWithVolatile {
private volatile static SingletonDoubleCheckWithVolatile singleton;
private SingletonDoubleCheckWithVolatile(){}
private static SingletonDoubleCheckWithVolatile getInstance(){
if (singleton == null){
synchronized (SingletonDoubleCheckWithVolatile.class){
if (singleton == null){
singleton = new SingletonDoubleCheckWithVolatile();
}
}
}
return singleton;
}
}
区别仅仅是比上一种实现方式多了一个volatile关键字
public enum SingletonEnumHungry {
INSTANCE;
public static SingletonEnumHungry getInstance(){
return INSTANCE;
}
}
public class SingletonEnumLazy {
private SingletonEnumLazy(){}
private enum SingletonHolder{
INSTANCE;
private SingletonEnumLazy singleton;
SingletonHolder(){
this.singleton = new SingletonEnumLazy();
}
public SingletonEnumLazy getSingleton(){
return singleton;
}
}
public static SingletonEnumLazy getInstance(){
return SingletonHolder.INSTANCE.getSingleton();
}
}
public class SingletonStaticInnerClass {
private SingletonStaticInnerClass(){}
private static class SingletonHolder{
private static SingletonStaticInnerClass singleton = new SingletonStaticInnerClass();
}
public static SingletonStaticInnerClass getInstance(){
return SingletonHolder.singleton;
}
}
public class SingletonHungry {
private static SingletonHungry singleton = new SingletonHungry();
private SingletonHungry() {
//防止反射实例化对象
if (singleton != null)
throw new RuntimeException("the class object cannot be instantiated");
}
public static SingletonHungry getInstance() {
return singleton;
}
}
public class SingletonLazy {
private static SingletonLazy singleton;
private static int count = 0;
private SingletonLazy() {
System.out.println("实例化了:" + ++count + "次");
}
public static SingletonLazy getInstance() {
if (null == singleton) {
singleton = new SingletonLazy();
}
return singleton;
}
public static void main(String[] args) {
Runnable task = SingletonLazy::getInstance;
// 模拟多线程环境下使用 Singleton 类获得对象
for (int i = 0; i < 10; i++) {
new Thread(task, "" + i).start();
}
}
}