• 6.22Java多线程单例设计模式


    6.22Java多线程单例设计模式

    设计一个单例模式

    类与类之间的关系

    目标:对外只有一个对象

    介绍double-checking单例模式

    使用volatile进行锁定资源

    饿汉式:直接实例化了对象

    懒汉式:没有直接实例化对象

    DCL单例设计模式实例demo

    图示:

     

    package thread.rearrangement;

    /**
    * DCL单例模式:
    * 1、在多线程环境下,对外存在一个对象--->外部不能new对象--->构造器私有化,避免外部new构造器(懒汉式加入并发控制)
    * 2、内部提供私有的静态属性--->存储对象的地址
    * 3、对外部提供公共的静态方法--->获取属性(该属性存了对象的地址)
    * @since JDK 1.8
    * @date 2021/6/22
    * @author Lucifer
    */
    public class DoubleCheckedLocking {

       /*提供私有的静态属性*/
       private static volatile DoubleCheckedLocking instance;
       //如果没有volatile其他线程可能访问到一个没有初始化的对象

       /*构造器私有化*/
       private DoubleCheckedLocking(){

      }

       /*提供公共的静态方法访问私有属性*/
       public static DoubleCheckedLocking getInstance(){

           /*如果已经存在对象,直接返回--->doublechecking避免不必要的同步(已经存在对象)*/
           if (null!=instance){
               /*直接返回结果*/
               return instance;
          }

           /*加入同步块锁住类--->class对象*/
           synchronized (DoubleCheckedLocking.class){
               /*当没有对象的时候返回对象*/
               if (null==instance){

                   /*创建一个对象*/
                   instance = new DoubleCheckedLocking();

                   /*
                   在这里考虑指令重排
                   在实例化一个对象的时候步骤:
                   1、开辟空间
                   2、初始化对象信息(对、块、栈)
                   3、返回对象地址给引用
                   如果构造器很慢,就有可能下面的内容先执行。
                   举例:
                   A还在初始化对象
                   B已经拿到了引用
                   就会形成空对象!!!
                   如何避免?
                   在属性前加入volatile保证可见性
                    */
              }
          }

           /*返回类对象*/
           return instance;

      }

       public static void main(String[] args) {
           Thread t = new Thread(()-> {
               System.out.println(DoubleCheckedLocking.getInstance());
          });
           t.start();

           if (t.equals(DoubleCheckedLocking.getInstance())){
               System.out.println(DoubleCheckedLocking.getInstance());
          }else {
               System.out.println("Error!");
          }

           /*直接输出DoubleCheckedLocking.getInstance就不会出现指令重排*/
           System.out.println(DoubleCheckedLocking.getInstance());

           /*
           这里也发生了指令重排的情况
           因为Thread是实例化线程,DoubleCheckedLocking.getInstance是直接获取地址
           所以先执行了下面的if判断
           所以执行的结果是先打印处了Error后打印出了getInstance的地址
            */

      }
    }
    /*
    1、如果两个线程A、B进入线程
    2、A进入创建对象但是耗时时间长
    3、B进入时候A对象没有写回主存,导致B也创建了一个对象
    这样就形不成单例设计模式了,所以要加入同步块
    1、锁住类的.class对象(类的模子)
    2、多个线程进入,就不会造成多线程创建多个对象
    如果已经存在对象则不需要等待,所以需要doublechecking再次监测
    */

     

    It's a lonely road!!!
  • 相关阅读:
    bzoj3109【CQOI2013】新数独
    HDU 1015 Safecracker(第一次用了搜索去遍历超时,第二次用for循环能够了,思路一样的)
    从头认识java-15.1 填充容器(3)-填充Map
    写一个python的服务监控程序
    javaScript定义函数的三种方式&变量的作用域
    android开发中应该注意的问题
    某技术大牛的帖子(android项目总结)
    android命名规范
    GitHub使用教程for Eclipse
    Android内存性能优化(内部资料总结)
  • 原文地址:https://www.cnblogs.com/JunkingBoy/p/14921557.html
Copyright © 2020-2023  润新知