单例模式:确保一个类只有一个实例,并提供一个全局访问点。
饿汉式
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton (){
}
public static Singleton getInstance() {
return instance;
}
}
这种方式基于classloder机制避免了多线程的同步问题,instance在类装载时就实例化了。 但是也不能确定有其他的方式(或者其他的静态方法)导致类装载,这时候初始化instance显然没有达到懒加载的效果。
懒汉式(非线程安全)
public class Singleton {
private static Singleton instance;
private Singleton (){
}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
在用户第一次调用getInstance()时初始化,在多线程情况无法保证正常实例化(全局只实例化一次)。
懒汉式(线程安全)
public class Singleton {
private static Singleton instance;
private Singleton (){
}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
通过增加synchronized
关键字修饰getInstance()
方法,迫使每个线程在进入这个方法之前,要先等候别的线程离开该方法,也就是说,不会有多个线程同时进入该方法,达到线程安全。但是,这样可能造成程序执行效率下降,拖垮性能。
双重检查锁(double-checked locking)
public class Singleton {
private volatile static Singleton instance;
private Singleton (){
}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return singleton;
}
}
valatitle
关键字确保:当instance变量被初始化成Singleton实例时,多个线程正确地处理instance变量。
DCL优点是资源利用率高,第一次执行getInstance()
时单例对象才被实例化,效率高。缺点是第一次加载时反应稍慢一些,在高并发环境下也有一定的缺陷,虽然发生的概率很小。DCL虽然在一定程度解决了资源的消耗和多余的同步,线程安全等问题,但是他还是在某些情况会出现失效的问题。
静态内部类
public class Singleton {
private Singleton(){
}
public static Singleton getInstance(){
return SingletonHolder.sInstance;
}
private static class SingletonHolder {
private static final Singleton sInstance = new Singleton();
}
}
Singleton类在类装载时并不会实例化,只有第一次调用getInstance()
时,虚拟机装载SingletonHolder
并初始化sInstance
。达到延时加载的效果,并且是线程安全的。
枚举
public class NetWrok {
}
public enum Singleton {
INSTANCE;
private NetWork net;
private Singleton() {
net = new NetWork();
}
public NetWork getNet() {
return net;
}
}
使用枚举除了线程安全和防止反射强行调用构造器之外,还提供了自动序列化机制,防止反序列化的时候创建新的对象。