彻底玩转单例模式

导读:本篇文章讲解 彻底玩转单例模式,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

彻底玩转单例模式

你在哪些地方用到过volatile?

饿汉式。DCL懒汉式,深究单例模式!

1:饿汉式:

package com.baidu.single;

//饿汉式单例
public class Hungry {
    //一上来就加载对象;

    //可能会浪费空间;
    private byte[] bytes1 = new byte[1024 * 1024];
    private byte[] bytes2 = new byte[1024 * 1024];
    private byte[] bytes3 = new byte[1024 * 1024];
    private byte[] bytes4 = new byte[1024 * 1024];

    //构造方法私有化;
    private Hungry(){

    }

    private final static Hungry HUNGRY = new Hungry();

    public static Hungry getInstance(){
        return HUNGRY;
    }

}

2:DCL懒汉式

package com.baidu.single;

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;

/**
 * 双重检测锁,加原子性操作;Vlatile不会被指令重排
 */
public class LazyMan {
    //如果两个反射去破环,可以用我们的红绿灯
    private static boolean flag = false;


    private LazyMan(){
        synchronized (LazyMan.class){
            if (flag == false){
                flag = true;
            }else {
                throw new RuntimeException("不要试图使用反射破坏异常");
            }

//            if (LazyMan!=null){
//                throw new RuntimeException("不要试图使用反射破坏异常");
//            }
        }
        System.out.println(Thread.currentThread().getName()+"OK");
    }

    private volatile static LazyMan LazyMan;

    //双重检测锁模式的懒汉式单例:简称DCL 懒汉式(Double Check Lock 双重检查锁定)
    public static LazyMan getInstance(){
        if (LazyMan == null){  //如果不判断,那么每次访问这个方法不管该对象是否已经创建都要进入同步代码块,线程数一多,资源消耗也是非常巨大的。
            synchronized (LazyMan.class){
                if (LazyMan == null){
                    LazyMan = new LazyMan();// 不是一个原子性操作。
//                    这和volatile不保证原子性不冲突,正因为不保证原子所以指令重排的作用才得以体现
                    /**
                     * 1:分配内存空间;
                     * 2;执行构造方法,初始化都对象。
                     * 3:把这个对象指向这个空间;
                     * 可能会发生指令重排现象;
                     * 期望123 A
                     * 可能执行132 B   //此时还没有完成构造
                     */
                }
            }
        }

        return LazyMan;
    }

    //反射!
    public static void main(String[] args) throws Exception {
        //LazyMan instance1 = LazyMan.getInstance();
        Field flag = LazyMan.class.getDeclaredField("flag");
        flag.setAccessible(true);

        //运用反射,获得构造器方法;
        Constructor<LazyMan> declaredConstructor = LazyMan.class.getDeclaredConstructor(null);
        declaredConstructor.setAccessible(true); //无视了私有的构造器;
        LazyMan instance1 = declaredConstructor.newInstance(); //这里用两个反射去破环
        flag.set(flag,false); //单例又被破坏

        LazyMan instance2 = declaredConstructor.newInstance();

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

        //com.baidu.single.LazyMan@45ee12a7
        //com.baidu.single.LazyMan@330bedb4
        /**
         * 结论:反射可以破坏这种单例模式
         */


    }
}

3:静态内部类;

package com.baidu.single;

import java.lang.reflect.Constructor;

//静态内部类;
public class Holder {

    private Holder(){
    }

    public static  Holder getInstance(){
        return InnerClass.holder;
    }

    public static class InnerClass{
        private static final Holder holder = new Holder();
    }

    public static void main(String[] args) throws Exception {
        Holder instance1 = Holder.getInstance();

        Constructor<Holder> declaredConstructor = Holder.class.getDeclaredConstructor(null);
        declaredConstructor.setAccessible(true);  // 无视私有的构造方法;
        Holder instance2 = declaredConstructor.newInstance();  //用反射去破坏;

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


    }


}

4:枚举(Enum)

package com.baidu.single;

import java.lang.reflect.Constructor;

//enum 是什么,? 本身就是一个Class类
public enum  EnumSingle {

    Instance;

    public EnumSingle getInstance(){
        return Instance;
    }

}

class Test{
    public static void main(String[] args) throws Exception {
        //java.lang.NoSuchMethodException: com.baidu.single.EnumSingle.<init>() 没有一个空参的构造器;

        EnumSingle instance1 = EnumSingle.Instance;
        Constructor<EnumSingle> declaredConstructor =  EnumSingle.class.getDeclaredConstructor(String.class,int.class);
        declaredConstructor.setAccessible(true);
        EnumSingle instance2 = declaredConstructor.newInstance();

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

在这里插入图片描述

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/71868.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!