• 单例正确写法


    Singleton正确写法:

    今天偶然看到设计模式,就复习了一下,这里再对单例进行一个回顾和总结。

    1.静态内部类

    public class Singleton {
    
        private Singleton(){
    
        }
    
        private static class SingletonFactory{
            private static Singleton instance = new Singleton();
        }
    
        public static Singleton getInstance(){
            return SingletonFactory.instance;
        }
    }
    

    2.枚举

    public enum SingtonEnum {
        INSTANCE;
        //method...
    }
    

    3.double-check

    public class Singleton {
        private static Singleton singleton = null;
    
        private Singleton(){
    
        }
    
        public static  Singleton getInstance2(){
            if(singleton==null){
               {
                    if (singleton==null){
                        singleton = new Singleton();
                    }
                }
            }
            return singleton;
        }
    
    }
    

    double-check存在的问题

    问题是由指令重排造成的。

    对象创建的三个步骤:

    1.申请内存

    2.初始化

    3.引用指向内存地址

    指令重排后可能是1,3,2的顺序,两个线程同时访问会出现对象不为空但是没有初始化的问题,所以需要加上volatile,使用内存屏障来禁止指令重排序,来保证执行顺序。volatile保证了屏障前的一定先执行,屏障后的后执行,也就是保证对象一定是这3个操作是被一个线程执行完的,第二个线程拿到的对象是正确的。(但是这三个操作本身还是可以重排序的)

    虽然理论上这种单例模式不是线程安全的,但是我测试发现得到的都是相同的示例:

    /**
     * Created by wxg on 2018/8/14 17:02
     */
    public class SingletonTest {
        public static void main(String[] args) throws InterruptedException {
            ExecutorService service = Executors.newFixedThreadPool(10);
            CyclicBarrier cyclicBarrier = new CyclicBarrier(10);
            try {
                for (int i = 0; i < 10; i++) {
                    service.submit(new Run(cyclicBarrier, "thread-" + i));
                }
            } finally {
                service.shutdown();
            }
        }
    }
    
    class Run implements Runnable {
        private CyclicBarrier cyclicBarrier;
        private String threadName;
    
        Run(CyclicBarrier cyclicBarrier, String threadName) {
            this.cyclicBarrier = cyclicBarrier;
            this.threadName = threadName;
        }
    
        @Override
        public void run() {
            try {
                cyclicBarrier.await();
                System.out.println(threadName + "-> " + Singleton.getInstance2());
            } catch (InterruptedException | BrokenBarrierException e) {
                e.printStackTrace();
            }
        }
    }
    

    volatile可见性和禁止重排序

    可见性:强制CPU缓存失效,直接读内存。

    禁止重排序:使用内存屏障实现,顺序不能跨屏障。




    我的个人博客:老吴的博客 和CSDN保持同步,欢迎关注

  • 相关阅读:
    CentOS 7.x时间同步服务chrony配置详解
    Kerbernetes使用ConfigMap资源配置非铭感信息
    Kerbernetes的volume应用进阶
    Kerbernetes的volume基础应用
    Kerbernetes的Ingress资源管理
    Kerbernetes的Service资源管理
    Kerbernetes的Pod控制器
    一份较为详细的深度学习资料汇总
    相见恨晚的网站
    Bert 时代的创新(应用篇):Bert 在 NLP 各领域的
  • 原文地址:https://www.cnblogs.com/cnsec/p/13286669.html
Copyright © 2020-2023  润新知