单例模式

单例模式一定要扛得住并发。


单例模式有很多版本,包括双重检查,静态内部类,枚举,其他的写法也有,建议大家看深入浅出单实例SINGLETON设计模式

饿汉单例的话太一劳永逸,如果你碰上了那种要使用很多资源的类的单例,但是一时半会儿又用不上的情况,那么还是不要用了。我写的单例都是使用的时候才加载的那种,也就是所谓的懒汉式单例。

单例模式的特点总结为两私有一公开,随时注意静态(我认为是两处静态)两私有是指私有构造方法私有的指向自身的实例一公开是指公开的对外获取单例的方法随时注意静态是指:因为构造方法私有,所以你不能通过创建实例来调用方法,那么就只有通过类名来调用里面的静态方法,记忆的链式思维是这样的,获取单例的方法必须静态,这个方法要调用指向单例的实例,由于静态方法只能调用静态方法和静态变量,那么被调用的那个单例的实例也必须是静态的(多注意枚举那里)。

基本的模板
class Singleton {
    private Singleton(){}
    private static Singleton singleton = null;
    public static Singleton getSingleton() {
        return null;
    }
}
具体的实现

/**
 * Double check && volatile Edition
 * 双重检查volatile版本
 */
class DoubleCheckSingleton {
    private DoubleCheckSingleton(){}
    private static volatile DoubleCheckSingleton INSTANCE = null;
    public static DoubleCheckSingleton getSingleton() {
        if (INSTANCE == null) {
            synchronized (DoubleCheckSingleton.class) {
                if (INSTANCE == null) {
                    INSTANCE = new DoubleCheckSingleton();
                }
            }
        }
        return  INSTANCE;
    }
}

/**
 * Static inner class Edition
 * 静态内部类版本
 */
class InnerClassSingleton {
    private InnerClassSingleton(){}

    private static class SingletonHolder {
        private static final InnerClassSingleton INSTANCE = new InnerClassSingleton();
    }

    public static InnerClassSingleton getSingleton() {
        return SingletonHolder.INSTANCE;
    }
}

/**
 * Enum Edition
 * 枚举版本
 */
class EnumSingleton {
    private EnumSingleton(){}

    public static EnumSingleton getSingleton() {
        return singleton.INSTANCE.getSingleton();
    }

    enum singleton {
        INSTANCE;
        private EnumSingleton singleton;
        private singleton(){ singleton = new EnumSingleton();}
        private EnumSingleton getSingleton(){return singleton;}
    }
}

/**
 * 测试线程,在这里更改使用的版本,虽然这很不软件工程
 */
class SimpleThread implements Runnable {
    @Override
    public void run() {
        System.out.println(DoubleCheckSingleton.getSingleton());
    }
}

/**
 * 测试主入口
 */
public class SingletonVersions {
    public static void main(String[] args) {
        SimpleThread simpleThread = new SimpleThread();
        for (int i = 0; i < 100; i++) {
            Thread thread = new Thread(simpleThread);
            thread.start();
        }
    }
}

不知道大家注意到了没有,我这里这么多个类,就SingletonVersions是public的,而且这么多个代码全在一个文件也就是SingletonVersions.java里面,没错,但是大家注意,访问权限,没有写public的类只具有包访问权限。一个java文件里面只准存在一个public的类,但是还可以写其他的非public类,还可以写接口,枚举,我经常因为代码很短,图方便的话就写在一个类里面了。


泛型单例

这个提的人很少,但是是有他的存在价值的,比如你有很多个工具类,都想用单例模式来创建唯一对象来减小开销,那么写个泛型就是有必要了的。

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Created by Curry on 17/6/26.
 */

public class Singleton<T> {

    /**
     * 私有构造函数,在这里显得表鸡肋,没有任何作用
     * 但是处于对单例模式的尊重,要给全它定义中的,私有构造函数、私有静态自身实例,共有静态的获取单例的方法
     */
    private Singleton() {
    }

    /**
     * 私有,静态,并发哈希表,用于存储所有的实例的唯一单例,而且其本身也是静态唯一的
     */
    private static ConcurrentHashMap<Class, Object> map = new ConcurrentHashMap<>();

    /**
     * 公开,静态,泛型的获取对应类型的单例
     */
    public static <T> T getDefault(Class<T> type) {
        if (map.get(type) == null) {
            synchronized (map) {
                if (map.get(type) == null) {
                    try {
                        /**
                         * 这里利用反射,将私有的构造方法改为共有的,用于创建实例,否则无法创建实例
                          */
                        Constructor constructor = type.getDeclaredConstructor();
                        constructor.setAccessible(true);
                        map.put(type, constructor.newInstance());
                    } catch (NoSuchMethodException e) {
                        e.printStackTrace();
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    } catch (InstantiationException e) {
                        e.printStackTrace();
                    } catch (InvocationTargetException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        return (T)map.get(type);

    }

    /**
     * 根据类型移除存储在哈希表中的单例
     */
    public static <T> void removeSingleton(Class<T> type) {
        map.remove(type);
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容