Singleton pattern
什么是单例模式 ?
单例模式是软件开发中的一种设计模式,它的作用在于可以限制我们实例化对象的次数(即一个对象只能初始化一次),以此减少开辟内存空间,节省系统资源.
单例模式的书写
1.双重锁(DLC)
/**
* If the code is not wrong its author is JokerCats.
*/
public class Singleton {
// 因为newInstance方法中的判断依据为instance,所以应该保证
// instance与newInstance同为static修饰(不要忘记给instance对象设置初始值)
private static Singleton instance = null;
// 因为是单例模式,为了限制我们创建Singleton对象的次数
// 所以将创建方法的权限设置为私有(外部不可随意调用)
private Singleton() {
}
// 向外部暴露一个静态方法用来实例化我们的Singleton对象
// 但由于该对象还没有被创建出来,导致不能直接调用该类中的方法
// 所以在该方法前加static进行修饰,用类名.方法的方式进行创建
public static Singleton newInstance() {
if (null == instance) {
// 提高性能,如果对象不为空 表示该对象已经被创建了,所以直接使用已经创建的就好
synchronized (Singleton.class) {
// 因为线程是抢占式运行,所以通过加锁的方式让线程更为安全
if (instance == null) {
// 在第一进来的时候判断对象是否为空,如果为空就进行创建
instance = new Singleton();
}
}
}
// 此处返回我们创建的对象
return instance;
}
}
2.懒汉式
public class Singleton {
// 采用静态内部类的形式
private static class LazyHolder{
// 这种形式虽然该Singleton被装载了,但是INSTANCE对象却不一定被初始化
// 只有调用了newInstance方法的时候才会进行实例化
private static final Singleton INSTANCE = new Singleton();
}
// 将创建方法的权限设置为私有(外部不可随意调用)
private Singleton(){
}
// 对外部暴露一个静态方法,并将该方法用static进行修饰,方便直接用类名进行调用
public static Singleton newInstance(){
return LazyHolder.INSTANCE;
}
}
3.饿汉式
public class Singleton {
// 该写法的思路是,不论你是否使用,都先初始化好
private static final Singleton INSTANCE = new Singleton();
// 将创建方法的权限设置为私有(外部不可随意调用)
private Singleton() {
}
// 对外部暴露一个静态方法,并将该方法用static进行修饰,方便直接用类名进行调用
public static Singleton newInstance() {
// 然后调用该方法时,直接将已经初始化好的对象返回
return INSTANCE;
}
}
4.枚举 (如果不明白什么是枚举的Cats可以点击链接)
public enum Singleton {
INSTANCE;
public void newInstance(){
// 该写法Effective Java作者Josh Bloch提倡的方式
// 它不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象
}
}
5.原子引用
public class Singleton {
// 创建原子引用的对象
private static final AtomicReference<Singleton> INSTANCE = new AtomicReference<Singleton>();
public static Singleton getInstance() {
// 死循环,直到指定的退出为止(个人认为该写法与Linux中的自旋锁写法有异曲同工之妙)
for (; ; ) {
// INSTANCE.get 是从AtomicReference的对象中查找元素(加入AtomicReference中的元素能保证原子性)
// 如果能得到元素就说明已经创建了单例对象,如果没有就创建个单例对象并加入AtomicReference中
Singleton current = INSTANCE.get();
if (current != null) {
return current;
}
current = new Singleton();
// 先去AtomicReference中取值,如果取到的值与expect相等就将update以原子的方式设置进去
// 如果设置成功会返回true
if (INSTANCE.compareAndSet(null, current)) {
return current;
}
}
}
// 将创建方法的权限设置为私有(外部不可随意调用)
private Singleton() {
}
}