首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >那些能让人秀出花的单列模式

那些能让人秀出花的单列模式

作者头像
Lvshen
发布2022-05-05 16:36:37
发布2022-05-05 16:36:37
3920
举报

单列模式有很多种写法,以前我知道懒汉式饿汉式,其实还有很多的方法,并且可能还比懒汉式饿汉式更优良。

饿汉式

个人觉得最简单,类在加载时就 new出来了。

代码语言:javascript
复制
public class HungrySingleton {
    private static final HungrySingleton instance = new HungrySingleton();
    private HungrySingleton(){}
    public static HungrySingleton getInstance(){
        return instance;
    }
}

❝优点:线程安全、逻辑简单 缺点:如果这种写法被大量使用的话,导致内存开销增加

懒汉式

调用方法的时候才new,这种方式需要考虑线程安全问题。面试最喜欢问这个。

代码语言:javascript
复制
public class LazySimpleSingleton {
    private static volatile LazySimpleSingleton instance = null;     //(1)

    private LazySimpleSingleton(){
        if (instance != null) {
            throw new RuntimeException("该构造方法禁止获取");
        }
    }   //(2)

    public static LazySimpleSingleton getInstance() {
        if (instance == null) {
            synchronized (LazySimpleSingleton.class) {
                if (instance == null) {
                    instance = new LazySimpleSingleton();
                }
            }
        }    //(3)
        return instance;
    }
}

如上所示代码,(1)加了volatile,为了防止指令重排,如果不加,很可能第一个线程没有完全将其实例化完,第二个线程获取到的示例就会有问题。(2)在构造函数中加了判断,是为了防止被反射创建实例。(3)加了synchronized,为了全程安全,保证只创建一个实例。

内部类实现
代码语言:javascript
复制
public class LazyInnerClassSingleton {
    private LazyInnerClassSingleton() {
        if (LazyHolder.INSTANCE != null) {
            throw new RuntimeException("该构造方法禁止获取");
        }
    }

    public static final LazyInnerClassSingleton getInstance() {
        return LazyHolder.INSTANCE;
    }

    private static class LazyHolder {
        private static final LazyInnerClassSingleton INSTANCE = new LazyInnerClassSingleton();
    }
}

内部类会在调用的时候才加载,并只加载一次。利用这个特性可以实现 单列模式。

本地线程实现
代码语言:javascript
复制
public class ThreadLocalSingleton {
    private static final ThreadLocal<ThreadLocalSingleton> threadLocalInstance = ThreadLocal.withInitial(() -> new ThreadLocalSingleton());

    private ThreadLocalSingleton(){}

    public static ThreadLocalSingleton getInstance(){
        return threadLocalInstance.get();
    }

    public static void main(String[] args){
        ThreadLocalSingleton instance1 = ThreadLocalSingleton.getInstance();
        ThreadLocalSingleton instance2 = ThreadLocalSingleton.getInstance();

        System.out.println(instance1 == instance2);

    }

}

如上代码,利用ThreadLocal线程隔离的特性实现。

Map实现
代码语言:javascript
复制
public class ContainerSingleton {
    private ContainerSingleton(){}

    private static Map<String,Object> ioc = new ConcurrentHashMap<>();

    public static Object getInstance(String className) {
        synchronized (ioc) {
            if (!ioc.containsKey(className)) {
                Object obj = null;

                try {
                    Class.forName(className).newInstance();
                    ioc.put(className,obj);

                } catch (Exception e) {
                    e.printStackTrace();
                }
                return obj;
            } else {
                return ioc.get(className);
            }
        }
    }
}

仿照SpringIoc容器实现。

枚举实现
代码语言:javascript
复制
public enum  EnumSingleton {
    INSTANCE;

    private Object data;

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }

    public  EnumSingleton getInstance() {
        return INSTANCE;
    }

}

《Effective Java》作者力荐,线程安全,不用怕被暴力反射破解。

利用CAS实现
代码语言:javascript
复制
public class Singleton {
    private Singleton() {
    }

    private static AtomicReference<Singleton> singletonAtomicReference = new AtomicReference<>();

    public static Singleton getInstance() {
        while (true) {
            Singleton singleton = singletonAtomicReference.get();// 获得singleton
            if (singleton != null) {// 如果singleton不为空,就返回singleton
                return singleton;
            }
            // 如果singleton为空,创建一个singleton
            singleton = new Singleton();
            // CAS操作,预期值是NULL,新值是singleton
            // 如果成功,返回singleton
            // 如果失败,进入第二次循环,singletonAtomicReference.get()就不会为空了
            if (singletonAtomicReference.compareAndSet(null, singleton)) {
                return singleton;
            }
        }
    }
}

好了,单列模式就分享都这里了。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-08-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Lvshen的技术小屋 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 饿汉式
  • 懒汉式
  • 内部类实现
  • 本地线程实现
  • Map实现
  • 枚举实现
  • 利用CAS实现
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档