赞
踩
单例模式(Singleton Pattern)是一种 创建型 设计模式,其目的是 确保一个类仅有一个实例,并提供一个 静态方法 来获取该实例。
单例模式围绕着两个特性展开:
共有以下六种实现方式:
饿汉式的实现在 Java 中有两种实现,常用的是第一种。
方式一:显式初始化。
public class Singleton {
private static final Singleton INSTANCE = new Singleton();
private Singleton() {}
public static synchronized Singleton getInstance() {
return INSTANCE;
}
}
方式二:静态代码块初始化。
public class Singleton {
private static final Singleton INSTANCE;
static {
INSTANCE = new Singleton();
}
private Singleton() {}
public static synchronized Singleton getInstance() {
return INSTANCE;
}
}
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
getInstance()
时才创建单例。singleton == null
这个条件,则它们会创建多个单例。注意 getInstance()
方法前的 synchronized
修饰符。
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
getInstance()
时才创建单例。synchronized
互斥锁,来保证只有一个线程能够生成单例,而其他线程等待这个线程创建的单例,保证了单例的线程安全。getInstance()
方法还得经过 加锁 和 释放锁 的流程(因为使用了 synchronized
互斥锁),降低了并发性能。注意单例前的 volatile
修饰符,它有两个作用:保证变量对所有线程可见 和 防止指令重排。在此处起 防止指令重排 的作用:防止 JIT 即时编译器对 instance = new Singleton();
这行代码进行重排序。
如果进行重排序,则可能先给 instance
分配内存(此时 instance != null
),然后才调用构造器为 instance
的属性赋值。在这两步操作之间,要是有线程调用 getInstance()
方法,它将无法通过外层的 instance == null
条件,会返回一个不完整(赋值不完全)的对象。
public class Singleton { private static volatile Singleton instance; // 注意 volatile 在这里起 防止指令重排 的作用 private Singleton() {} public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; } }
getInstance()
时才创建单例。instance == null
条件,则在内层使用 synchronized
互斥锁,来保证只有一个线程创建单例,而其他线程等待这个线程创建的单例,保证了单例的线程安全。public class Singleton {
private Singleton() {}
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
getInstance()
时,才会 触发静态内部类的加载,从而创建单例。public enum Singleton {
INSTANCE; // 直接使用 Singleton.INSTANCE 就可以获取到单例
// 可以随意写方法和属性,就像在类中一样
}
private Singleton() {}
。public class Singleton {
private static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
instance = new Singleton();
}
}
return instance;
}
}
这样的单例模式是 线程不安全 的,synchronized
互斥锁没有起到应有的作用。只要多个线程都能通过 instance == null
条件,则它们每个线程都会创建一次单例,synchronized
仅仅能保证同一时刻只有一个线程在创建单例罢了。
应该将 判断 和 赋值 都放到 synchronized
互斥锁里,就像单例的 第三种实现——懒汉式 ( 线程安全 ) 一样。
在JDK中,Runtime
类使用了 饿汉式单例,代码如下:
public class Runtime {
private static final Runtime currentRuntime = new Runtime();
public static Runtime getRuntime() {
return currentRuntime;
}
private Runtime() {}
// ...
}
其中,singleton
属性和 Singleton()
构造器都是 私有的,而 getInstance()
方法是 公开的。此外,singleton
属性和 getInstance()
方法都是 静态的。
在单例模式中,只有一个角色 Singleton
,它负责 实现返回单例的 静态 方法。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。