栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

彻底玩懂单例模式

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

彻底玩懂单例模式

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

一、单例模式是什么?

单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

二、简单实现(饿汉式的单例和懒汉式的单例)

1.饿汉式

public class esingle {
    private static esingle single =new esingle("张三");
    private String name;
    private esingle(Str
ing name){
            this.name=name;
    }
    public static esingle getInstance(){
        return single;
    }

    public static void main(String[] args) {
        esingle instance = esingle.getInstance();
        esingle instance1 = esingle.getInstance();
        System.out.println(instance);
        System.out.println(instance1);
        System.out.println(instance == instance1);
    }
}

2.懒汉式

public class esingle {
    private static esingle single;
    private String name;
    private esingle(String name){
            this.name=name;
    }
    public static esingle getInstance(){
        if (single==null){
             single=new esingle("张三");
        }
        return single;
    }


    public static void main(String[] args) {

        esingle instance = esingle.getInstance();
        esingle instance1 = esingle.getInstance();
        System.out.println(instance);
        System.out.println(instance1);
        System.out.println(instance == instance1);
    }
}
以上是单例模式的简单实现,但只适用于单一线程(只在单一线程安全),在多线程下是不安全的,原因可以自己百度一下,这里就不详解了。 三、实现在多线程下看上去安全的单例模式(以懒汉式为例)

代码如下(示例):

public class esingle {
    private volatile static esingle single;
    private static boolean zrf=false;
    private String name;
    private esingle(String name){
        synchronized (esingle.class){
            if (zrf==false){
                zrf=true;
                this.name=name;
            }else{
                throw new RuntimeException("实例化失败");
            }
        }

    }
    //双重锁检查
    public static esingle getInstance(){
        if (single==null){
            synchronized (esingle.class){
                if (single==null){
                    single=new esingle("张三");
                }
            }
        }
        return single;
    }
    public static void main(String[] args) throws Exception {
        //用线程池进行测试
        Executor executor=new ThreadPoolExecutor(
               5,10,60, TimeUnit.SECONDS,new LinkedBlockingQueue<>());
       for (int i = 0; i <100; i++) {
           executor.execute(()->{
               esingle instance = esingle.getInstance();
               System.out.println(instance);
            });
        }

    }
}
这样实现单例在多线程下是绝对安全的,但是如果你接触过java的反射知识就可破坏这种单例模式,
你可以在main方法中执行以下代码
 Field zrf = esingle.class.getDeclaredField("zrf");
        zrf.setAccessible(true);
        Constructor declaredConstructor = esingle.class.getDeclaredConstructor(String.class);
        declaredConstructor.setAccessible(true);
        esingle lis = declaredConstructor.newInstance("李四");
        zrf.set(lis,false);
        esingle wanwu = declaredConstructor.newInstance("王五");
        System.out.println(wanwu);
        System.out.println(lis);
        System.out.println(wanwu==lis);

执行结果如下

你会惊讶的发现单例被破坏了,那么反射就是无敌的了吗?

请看以下JDK newInstance的源码

public T newInstance(Object ... initargs)
        throws InstantiationException, IllegalAccessException,
               IllegalArgumentException, InvocationTargetException
    {
        if (!override) {
            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
                Class caller = Reflection.getCallerClass();
                checkAccess(caller, clazz, null, modifiers);
            }
        }
        if ((clazz.getModifiers() & Modifier.ENUM) != 0)
            throw new IllegalArgumentException("Cannot reflectively create enum objects");
        ConstructorAccessor ca = constructorAccessor;   // read volatile
        if (ca == null) {
            ca = acquireConstructorAccessor();
        }
        @SuppressWarnings("unchecked")
        T inst = (T) ca.newInstance(initargs);
        return inst;
    }

从中我们可以看出反射是不可以破坏枚举类型的类的(枚举类型天生就是单例的),所有我们可以继续完善我们的代码,

终极单例模式
public enum esingle {
    ESINGLE("张三");
    private  static boolean zrf=false;
    private String name;
    private esingle(String name){
                this.name=name;
    }
    public synchronized static esingle getInstance(){
        return ESINGLE;
    }
}

由于枚举类型的特性我们只能使用饿汉式实现,现在这个单例是目前为主最安全的,不仅是多线程安全,而且无法被反射破坏。

暑期编程PK赛 得CSDN机械键盘等精美礼品!
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1016720.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号