先来说说为什么要使用单例模式进行架构方面的设计,那就是单例模式的优点:
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几种实现方式,但是设计时需要考虑多线程的场景,大家根据实际情况择优选择
来源:CSDN
作者:mischen520
链接:https://blog.csdn.net/miachen520/article/details/104104474