在前段时间集中练习了较长时间有关数据结构的相关问题,积累了一定的算法思想。大概有一周左右的样子没有更新博文了,今天先不和大家分享算法题目啦,在JavaEE互联网框架一书中第二章讲到了设计模式,但恰巧书中讲了很多种设计模式,唯独没有单列模式的讲解,大概是默认比较简单所以没有讲解吧,所以由此引发了一个比较严重的问题,面试中单例模式可能越发容易被人忽略了,也因此单例模式也就变成了面试的重灾区,越是简单越讲不清,况且可能你了解的单例模式远远无法满足面试官的要求,所以在这里想和大家再一起来深入了解一下单例模式从而给予我们更多的帮助~
首先我们介绍一下单例模式有哪些特点:
1、单例类只能有一个实例。
2、单例类必须自己创建自己的唯一实例。
3、单例类必须给所有其他对象提供这一实例。
下面我们就来看一下Java中有哪些单例模式吧,当然多种单例模式都必须是在定义基础上的变形......
懒汉式单例:
public class Singleton {
private Singleton() {}
private static Singleton single=null;
//静态工厂方法
public static Singleton getInstance() {
if (single == null) {
single = new Singleton();
}
return single;
}
}
上述代码存在线程安全中的check-then-act问题,解决方法是可以在方法定义中加入synchronize关键字修饰,当然也可以把条件判断语句放入synchronize块使得操作具有原子性即可。
饿汉式单例:
public class Singleton1 {
private Singleton1() {}
private static final Singleton1 single = new Singleton1();
//静态工厂方法
public static Singleton1 getInstance() {
return single;
}
}
饿汉式在类创建的同时就已经创建好一个静态的对象供系统使用,以后不再改变,所以是线程安全的,因为饿汉式在类创建的同时就实例化一个静态对象出来,不管之后会不会使用这个单例,都会占据一定的内存,但是相应的,在第一次调用时速度也会更快,因为其资源已经初始化完成。
双重锁机制:
public class Singleton {
private volatile static Singleton singleton;
private Singleton (){}
public static Singleton getSingleton() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
上述是实现方式是线程安全的,且在多线程环境下能够保持高性能,静态工厂方法的性能对程序很关键。
登记式单例:
public class Singleton {
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton (){}
public static final Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
这种方式能达到双检锁方式一样的功效,但实现更简单。对静态域使用延迟初始化,应使用这种方式而不是双检锁方式。这种方式只适用于静态域的情况,双检锁方式可在实例域需要延迟初始化时使用。这种方式同样利用了 classloder 机制来保证初始化 instance 时只有一个线程,它跟饿汉式单例不同的是:后者只要 Singleton 类被装载了,那么 instance 就会被实例化(没有达到 lazy loading 效果),而这种方式是 Singleton 类被装载了,instance 不一定被初始化。因为 SingletonHolder 类没有被主动使用,只有通过显式调用 getInstance 方法时,才会显式装载 SingletonHolder 类,从而实例化 instance。想象一下,如果实例化 instance 很消耗资源,所以想让它延迟加载,另外一方面,又不希望在 Singleton 类加载时就实例化,因为不能确保 Singleton 类还可能在其他的地方被主动使用从而被加载,那么这个时候实例化 instance 显然是不合适的。
单例模式大概就介绍到这里了,一般介意大家使用饿汉式单例,如果有其他特别要求再去尝试双重锁单例与登记式单例,而懒汉式单例则有一定的性能瓶颈,所以不介意使用。好啦,希望大家关于单例模式都可以理解掌握且熟练应用哈~