定义:
确保一个类只有一个实例,并提供一个全局访问点来访问这个唯一的实例。
单例模式是一种对象创建型模式。单例模式有三个要点:一是某个类只能有一个实例;二是他必须自行创建这个实例;三是它必须自行向整个系统提供这个实例
饿汉式单例:
当类被加载的时候,静态变量instance就会被初始化,此时类的私有构造函数将被调用,单例类的唯一实例将被创建。
public class EagerSingleton {
private static final EagerSingleton Instance= new EagerSingleton();
private EagerSingleton() {
}
public static EagerSingleton getInstance() {
return Instance;
}
}
懒汉式单例:
懒汉式单例类的构造函数也是私有的,与饿汉式单例类不同的是,饿汉式单例类在第一次被引用时将自己实例化,懒汉式单例类在加载时不会将自己实例化,而是第一次调用getInstance()方法时实例化。这种技术又称为延迟加载技术。为了避免多个线程同时调用getInstance方法,可以使用关键字synchronized。
public class LazySingleton {
private static LazySingleton Instance=null;
private LazySingleton() {
}
synchronized public static LazySingleton getInstance() {
if(Instance==null) {
Instance = new LazySingleton();
}
return Instance;
}
}
对方法加锁可以处理多个线程同时访问的问题,虽然解决了线程安全的问题,但是每次调用需要进行线程锁定判断,在多线程高并发环境中将会导致系统性能大大降低。所以还可以进行改进,在创建实例处进行加锁。
public class LazySingleton {
private static LazySingleton Instance=null;
private LazySingleton() {
}
public static LazySingleton getInstance() {
if(Instance==null) {
synchronized (LazySingleton.class) {
Instance = new LazySingleton();
}
}
return Instance;
}
}
但是这种情况又回到了原来的线程不安全的,还是会存在单例对象不唯一的情况。线程A和线程B同时调用getInstance()方法时均能通过if条件判断。只是先拿到锁的线程先创建一个Instance。所以需要进一步改进加上双重判断。需要注意双重检查锁定需要在静态成员变量前加上修饰符volatile。因为别volatile修饰的成员变量可以确保多个线程都能够正确处理。但是volatile会屏蔽虚拟机所做的一些优化,可能会导致系统性能降低
public class LazySingleton {
private volatile static LazySingleton Instance=null;
private LazySingleton() {
}
public static LazySingleton getInstance() {
if(Instance==null) {
synchronized(LazySingleton.class) {
if(Instance==null) {
Instance = new LazySingleton();
}
}
}
return Instance;
}
}
IODH:
为了解决饿汉式单例不能延迟加载,懒汉式线程安全控制繁琐,我们可以通过IODH技术来实现单例模式,在单例类中增加一个静态(static)内部类,在该内部类中创建单例对象,再将该单例对象通过getinstance()方法返回给外部使用。
public class IoDH {
private IoDH() {
}
private static class HolderClass{
private static final IoDH Instance = new IoDH();
}
public static IoDH getInstance() {
return HolderClass.Instance;
}
}