码迷,mamicode.com
首页 > 编程语言 > 详细

6.22Java多线程单例设计模式

时间:2021-06-23 16:54:04      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:contain   pre   admin   一个   外部   地址   ade   min   use   

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再次监测
*/

 

6.22Java多线程单例设计模式

标签:contain   pre   admin   一个   外部   地址   ade   min   use   

原文地址:https://www.cnblogs.com/JunkingBoy/p/14921557.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!