单例设计模式
github : https://github.com/zhang-shoukang/design-pattern
单例设计模式在面试的被问到的几率太大了,大多数问的都是,你能说粗来多少种单例设计模式。
如果你只能说出来懒汉式,饿汉式,估计面试官对你也就彻底失望了。
如果你能说出来四五种,那估计面试官对你印象还不错。
但是如果你能说出来七八种,那估计这次面试就妥了。
1.是什么?
单例对象(Singleton)是一种常用的设计模式。在Java应用中,单例对象能保证在一个JVM中,该对象只有一个实例存在。
2.这种设计模式的好处:
1、某些类创建比较频繁,对于一些大型的对象,这是一笔很大的系统开销。
2、省去了new操作符,降低了系统内存的使用频率,减轻GC压力。
3、有些类如交易所的核心交易引擎,控制着交易流程,如果该类可以创建多个的话,系统完全乱了。(比如一个军队出现了多个司令员同时指挥,肯定会乱成一团),所以只有使用单例模式,才能保证核心交易服务器独立控制整个流程。
3. 8种不同的单例设计模式
3.1
//懒汉式 /** * 好处: 用到改实例的时候,才会实例化该对象,不会浪费资源 * 坏处:非线程安全,多线程环境下,会创建多个实例。 */
@NotThreadSafe
@NotRecommend
public class Singleton01 {
private static Singleton01 singleton01;
private Singleton01(){};
public static Singleton01 getInstance(){
if (singleton01==null){ //point
singleton01 = new Singleton01();
}
return singleton01;
}
}
3.2
//饿汉式 /** * 好处:线程安全,从始至终只有一个实例 * 坏处:丢失了延迟实例化,资源可能浪费 */
@ThreadSafe
@NotRecommend
public class Singleton02 {
private Singleton02 singleton02 = new Singleton02();
private Singleton02(){}
public Singleton02 getSingleton02() {
return singleton02;
}
}
3.3
//懒汉式 加锁 /** * 好处:通过加锁保证了线程安全 * 坏处:因为加锁,带来的性能问题 (一次只能有一个线程被处理) */
@ThreadSafe
@NotRecommend
public class Singleton03 {
private Singleton03 singleton03 =null;
private Singleton03(){};
public synchronized Singleton03 getSingleton03() {
if (singleton03==null){
singleton03=new Singleton03();
}
return singleton03;
}
}
3.4
//双重校验锁 /** *优点:保证了单例,和延迟加载 *缺点:但是有可能会出现安全问题。 */ /** * 对象初始化顺序: * 1. memory= allocate() 分配对象的内存空间 * 2.constructor Instance 对象初始化 * 3. instance=memory 设置instance 指向刚刚分配的内存 * * 但是多线程情况下,会出现jdk和jvm的优化,有可能会发生指令重排 * 顺序变为如下: * 1. memory= allocate() 分配对象的内存空间 * 3. instance=memory 设置instance 指向刚刚分配的内存 * 2.constructor Instance 对象初始化 * * 故障重演: * 线程A: 执行到 singleton04=new Singleton04(); 因为发生指令重拍,出现了上面的顺序。 * 线程B: 执行到 第一个 if (singleton04==null){ 发现singleton04 不为null ,return singleton04 * 程序其他地方如果用到了返回的singleton04 ,就会报NullPointException */
@NotThreadSafe
@NotRecommend
public class Singleton04 {
private Singleton04(){}
private static Singleton04 singleton04=null;
public static Singleton04 getInstance(){
if (singleton04==null){
synchronized (Singleton04.class){
if (singleton04==null){
singleton04=new Singleton04();
}
}
}
return singleton04;
}
}
3.5
//双重校验锁 + validate 防止指令重排 /** *优点: 加入validate 避免指令重排,线程安全 * 缺点:还是加锁 */
@ThreadSafe
@NotRecommend
public class Singleton05 {
private Singleton05(){}
private volatile static Singleton05 singleton05=null;
public static Singleton05 getInstance(){
if (singleton05==null){
synchronized (Singleton05.class){
if (singleton05==null){
singleton05=new Singleton05();
}
}
}
return singleton05;
}
}
3.6
//饿汉模式 //单例实例在类装载时进行创建 /** * 优点:在类装载的时候进行一次初始化,线程安全 * 缺点:提前初始化,可能会浪费资源(如果一直没用到) */
@ThreadSafe
@NotRecommend
public class Singleton06 {
private Singleton06(){}
public static Singleton06 singleton06=null;
static {
singleton06 = new Singleton06();
}
public static Singleton06 singleton06(){
return singleton06;
}
}
3.7
//静态内部类实现 /** * 优点:当Singleton07加载的时候,SingletonHoler不会加载进入内存,只有当真正调用getInstance方法,才会加载,初始化INSTANCE * 而且可以达到延迟加载的目的,而且由虚拟机提供了对线程安全的支持。 */
@ThreadSafe
@Recommend
public class Singleton07 {
private Singleton07(){}
private static class SingletonHoler{
private static final Singleton07 INSTANCE = new Singleton07();
}
public static Singleton07 getInstance(){
return SingletonHoler.INSTANCE;
}
}
3.8
//枚举方式 /** * 优点: 最安全 * // JVM保证这个方法绝对只调用一次 //Singleton() { //singleton = new SingletonExample7(); //} */
@ThreadSafe
@Recommend
public class Singleton08 {
private Singleton08(){}
public static Singleton getInstance(){
return Singleton.INSTANCE.getSingleton();
}
private enum Singleton{
INSTANCE;
public Singleton singleton;
public Singleton getSingleton() {
return singleton;
}
}
}
4.总结
单例设计模式,种类繁多,用的时候可以根据需要选择。
JDK种具体实例,如 java.lang.Runtime#getRuntime()。