架构设计之-单例模式

ε祈祈猫儿з 提交于 2020-01-29 11:06:22

先来说说为什么要使用单例模式进行架构方面的设计,那就是单例模式的优点:

1.单例模式只有一个实例,节省了内存资源,对于一些需要频繁创建和销毁的对象,使用单例模式可以提高系统性能

2.单例模式可以设置系统的全局访问点,优化和共享数据。常见的系统架构设计中会经常使用单例模式就行设计,用来创建一个实例来就行读取相应的一些配置文件和公共类

代码实现:

1、饿汉式 (可用)

public class Singleton {

    private final static Singleton INSTANCE = new Singleton();
    
    private Singleton(){}

    public static Singleton getInstance(){
        return INSTANCE;
    }

}

这是比较常见的写法,在类加载的时候就完成了实例化,避免了多线程的同步问题。当然缺点也是有的,因为类加载时就实例化了,没有达到Lazy Loading (懒加载) 的效果,如果该实例没被使用,内存就浪费了。

2、普通的懒汉式 (线程不安全,不可用)

public class Singleton {

    private static Singleton instance = null;

    private Singleton() {
    }

    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }

}

 

这是懒汉式中最简单的一种写法,只有在方法第一次被访问时才会实例化,达到了懒加载的效果。但是这种写法有个致命的问题,就是多线程的安全问题。假设对象还没被实例化,然后有两个线程同时访问,那么就可能出现多次实例化的结果,所以这种写法不可采用。

3、同步方法的懒汉式 (可用)

public class Singleton {

    private static Singleton instance = null;

    private Singleton() {
    }

    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }

}

 

这种写法是对getInstance()加了锁的处理,保证了同一时刻只能有一个线程访问并获得实例,但是缺点也很明显,因为synchronized是修饰整个方法,每个线程访问都要进行同步,而其实这个方法只执行一次实例化代码就够了,每次都同步方法显然效率低下,为了改进这种写法,就有了下面的双重检查懒汉式。
4、双重检查懒汉式 (可用,推荐)

package com.mischen.it.util;

/*
 * mischen 
 * 双重检查懒汉式,可用,推荐的写法
 * 这种写法用了两个if判断,也就是Double-Check,并且同步的不是方法,而是代码块,效率较高,是对第三种写法的改进。
 * 为什么要做两次判断呢?这是为了线程安全考虑,还是那个场景,对象还没实例化,两个线程A和B同时访问静态方法并同时运行到第一个if判断语句,
 * 这时线程A先进入同步代码块中实例化对象,结束之后线程B也进入同步代码块,
 * 如果没有第二个if判断语句,那么线程B也同样会执行实例化对象的操作了
 */
public class Singleton {
	
	private static volatile Singleton instance;
	
	private Singleton(){
		
	}
	
	public static Singleton getInsance(){
		if (instance==null){
			synchronized (Singleton.class){
				if (instance==null){
					instance=new Singleton();
				}
			}
		}
		return instance;
	}
}

5、静态内部类 (可用,推荐)

public class Singleton {

    private Singleton() {}

    private static class SingletonInstance {
        private static final Singleton INSTANCE = new Singleton();
    }

    public static Singleton getInstance() {
        return SingletonInstance.INSTANCE;
    }

}

 

这是很多开发者推荐的一种写法,这种静态内部类方式在Singleton类被装载时并不会立即实例化,而是在需要实例化时,调用getInstance方法,才会装载SingletonInstance类,从而完成对象的实例化。同时,因为类的静态属性只会在第一次加载类的时候初始化,也就保证了SingletonInstance中的对象只会被实例化一次,并且这个过程也是线程安全的。
6、枚举 (可用、推荐)

public enum Singleton {
    INSTANCE;
}

这种写法在《Effective JAVA》中大为推崇,它可以解决两个问题:

1)线程安全问题。因为Java虚拟机在加载枚举类的时候会使用ClassLoader的方法,这个方法使用了同步代码块来保证线程安全。

2)避免反序列化破坏对象,因为枚举的反序列化并不通过反射实现。

上述就是6种单例模式的常见架构设计,比较常见的是1、4、5、6几种实现方式,但是设计时需要考虑多线程的场景,大家根据实际情况择优选择

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!