• java高级---->Thread之单例模式的使用


      这里我们介绍一下在多线程中如何安全正确的编写单例模式的代码。不知为何,恰如其分的话总是姗姗来迟,错过最恰当的时机。

    多线程中的单例模式

      这里面通过代码来体会一下在多线程中如何正确的编写单例模式的代码。相同的代码如下,不同的是Object这个类。

    package com.linux.huhx.thread3.singleDesign_1;
    
    /**
     * @Author: huhx
     * @Date: 2017-10-31 下午 4:28
     */
    public class SingleDesignTest1 {
        public static void main(String[] args) {
            MyThread[] threads = new MyThread[10];
            for (int i = 0; i < 10; i++) {
                threads[i] = new MyThread();
            }
            for (int i = 0; i < 10; i++) {
                threads[i].start();
            }
        }
    
        static class MyThread extends Thread {
            @Override
            public void run() {
                System.out.println(MyObject*.getInstance().hashCode());
            }
        }
    }

    以下的不同测试类的结果,都是基于修改MyThread里面run方法的MyObject*的值。

    一、立即加载方式(饿汉模式)

    public class MyObject1 {
        private static MyObject1 myObject = new MyObject1();
        private MyObject1() {}
    
        public static MyObject1 getInstance() {
            return myObject;
        }
    }

    安全:一次的打印结果如下

    1508118770
    1508118770
    1508118770
    1508118770
    1508118770
    1508118770
    1508118770
    1508118770
    1508118770
    1508118770

    二、延迟加载方式(懒汉模式)

    public class MyObject2 {
        private static MyObject2 myObject;
        private MyObject2() {}
    
        public static MyObject2 getInstance() {
            try {
                if (myObject == null) {
                    // 模拟一些准备的耗时操作
                    TimeUnit.SECONDS.sleep(2);
                    myObject = new MyObject2();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return myObject;
        }
    }

    不正确:一次的打印结果

    401241377
    355159803
    1875573029
    797782832
    1696014491
    1060834655
    961745937
    1060834655
    1312341120
    985396398

    三、延迟加载解决方案之声明synchronized

    public class MyObject3 {
        private static MyObject3 myObject;
        private MyObject3() {}
    
        public synchronized static MyObject3 getInstance() {
            try {
                if (myObject == null) {
                    // 模拟一些准备的耗时操作
                    TimeUnit.SECONDS.sleep(2);
                    myObject = new MyObject3();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return myObject;
        }
    }

    安全:一次的打印结果

    774263507
    774263507
    774263507
    774263507
    774263507
    774263507
    774263507
    774263507
    774263507
    774263507

    效率比较低下:同步运行,下一个线程想要取得对象,则必须等待上一个线程释放锁之后,才可以继续执行。

     四、延迟加载解决方案之同步代码块

    public class MyObject4 {
        private static MyObject4 myObject;
        private MyObject4() {}
    
        public static MyObject4 getInstance() {
            try {
                synchronized (MyObject4.class) {
                    if (myObject == null) {
                        // 模拟一些准备的耗时操作
                        TimeUnit.SECONDS.sleep(2);
                        myObject = new MyObject4();
                    }
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return myObject;
        }
    }

     安全:一次的打印结果如下

    1373650392
    1373650392
    1373650392
    1373650392
    1373650392
    1373650392
    1373650392
    1373650392
    1373650392
    1373650392

     效率比较低下:和上述的synchronized同步方法一样都是同步运行的。

    五、延迟加载解决方案之同步部分代码块

    public class MyObject5 {
        private static MyObject5 myObject;
        private MyObject5() {}
    
        public static MyObject5 getInstance() {
            try {
                if (myObject == null) {
                    // 模拟一些准备的耗时操作
                    TimeUnit.SECONDS.sleep(2);
                    synchronized (MyObject5.class) {
                        myObject = new MyObject5();
                    }
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return myObject;
        }
    }

    不安全:一次的打印结果如下

    401241377
    1696014491
    797782832
    1875573029
    1060834655
    43626537
    1971360294
    1312341120
    961745937
    860826410

    六、延迟加载解决方案之DCL双检查锁机制

    public class MyObject6 {
        private volatile static MyObject6 myObject;
        private MyObject6() {}
    
        public static MyObject6 getInstance() {
            try {
                if (myObject == null) {
                    // 模拟一些准备的耗时操作
                    TimeUnit.SECONDS.sleep(2);
                    synchronized (MyObject6.class) {
                        if (myObject == null) {
                            myObject = new MyObject6();
                        }
                    }
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return myObject;
        }
    }

    安全:一次的打印结果如下

    1312341120
    1312341120
    1312341120
    1312341120
    1312341120
    1312341120
    1312341120
    1312341120
    1312341120
    1312341120

    使用双重检查锁功能,成功地解决了“懒汉模式”遇到多线程的问题。DCL也是大多数多线程结合单例模式使用的解决方案。

    七、使用静态内置类实现单例模式

    public class MyObject7 {
        private static class MyObjectHandler {
            private static MyObject7 myObject = new MyObject7();
        }
    
        private MyObject7() {}
    
        public static MyObject7 getInstance() {
            return MyObjectHandler.myObject;
        }
    }

    安全:一次的打印结果如下

    1240673261
    1240673261
    1240673261
    1240673261
    1240673261
    1240673261
    1240673261
    1240673261
    1240673261
    1240673261

    八、使用static代码块实现单例模式

    public class MyObject8 {
        private static MyObject8 myObject = null;
    
        static {
            myObject = new MyObject8();
        }
    
        private MyObject8() {}
    
        public static MyObject8 getInstance() {
            return myObject;
        }
    }

    安全:一次的打印结果如下

    1875573029
    1875573029
    1875573029
    1875573029
    1875573029
    1875573029
    1875573029
    1875573029
    1875573029
    1875573029

    友情链接

  • 相关阅读:
    linux系列之-—03 压缩和解压缩命令
    Atlassian Confluence安装
    常见ODBC及OLEDB连接串的写法
    windows 怎么验证域名是否开启了 https
    Jenkins基础篇 系列之-—05 集成JIRA
    SVN系列之—-SVN版本回滚的办法
    JMeter 系列之—-02 创建数据库测试计划
    golang web框架 beego 学习 (一) 环境搭建
    补充 3:Golang 一些特性
    补充 1: panic 、recover、 defer
  • 原文地址:https://www.cnblogs.com/huhx/p/baseusejavasingleDesign.html
Copyright © 2020-2023  润新知