JAVA语言的单例模式实现教程
小标 2018-12-19 来源 : 阅读 649 评论 0

摘要:本文主要向大家介绍了JAVA语言的单例模式实现教程,通过具体的内容向大家展示,希望对大家学习JAVA语言有所帮助。

本文主要向大家介绍了JAVA语言的单例模式实现教程,通过具体的内容向大家展示,希望对大家学习JAVA语言有所帮助。


概述


使用一个私有构造函数、一个私有静态变量以及一个公有静态函数来实现。


私有构造函数保证了不能通过构造函数来创建对象实例,只能通过公有静态函数返回唯一的私有静态变量。


实现


懒汉式-线程不安全


以下实现中,私有静态变量uniqueInstance被延迟实例化,这样做的好处是,如果没有用到该类,那么就不会实例化uniqueInstance,从而节约资源。


  public class SingLeton{

  private static SingLeton uniqueInstance;

 

  private SingLeton(){

  }

 

  public static SingLeton getUniqueInstance(){

    if(uniqueInstance==null){

    uniqueInstance =new SingLeton();

    }

    return uniqueInstance;

  }

}

   



懒汉式-线程安全


只需要对getUniqueInstance()方法加锁,那么在一个时间点只能有一个线程能够进入该方法,从而避免了uniqueInstance进行多次实例化的问题。


但是这样有一个问题,就是当一个线程进入该方法后,其他线程视图进入该方法都必须等待,因此性能上有一定的损耗。


public static synchroinized SingLeton getUniqueInstance(){

    if(uniqueInstance ==null){

      uniqueInstance =new SingLeton();

      }

    return uniqueInstance;

}

   



饿汉式-线程安全


线程不安全问题主要由uniqueInstance被实例化了多次,如果uniqueInstance采用直接实例化的话,就不会被实例化多次,也就不会产生线程不安全的问题,但是直接实例化的方式也丢失了延迟实例化带来的节约资源的优势。


private static SingLeton uniqueInstance = new SingLeton();

   



双重校验锁-线程安全


uniqueInstance只需要被实例化一次,之后就可以直接使用了,加锁操作只需要对实例化那部分代码进行,也就是说,只有当uniqueInstance没有被实例化时,才需要进行加锁。


双重校验锁先判断uniqueInstance是否已经被实例化了,如果没有被实例化,那么才对实例化语句进行加锁。


public class SingLeton{

   private volatile static SingLeton uniqueInstance;

   private SinaLeton uniqueInstance;

 

  public static SingLeton getUniqueInstance(){

    if(uniqueInstance==null){

      synchronized(SingLeton.class){

        if(uniqueInstance == null){ 

            uniqueInstance = new SingLeton();

        }

      }

    }

    return uniqueInstance;

  }

}

   



考虑下面的实现,也就是只使用了一个if语句,在uniqueInstance==null的情况下,如果两个线程同时执行if语句,那么两个线程就会同时进入if语句块内,虽然在if语句块内有加锁操作,但是两个线程都会执行uniqueInstance=new SingLeton(),这条语句,只是早晚的问题,也就是说会进行两次实例化,从而产生了两个实例,因此必须使用双重校验锁,也就是需要使用两个if判断。


if(uniqueInstance == null){

  synchronized(SingLeton.class){

   uniqueInstance =new SingLeton();

  }

}

   



uniqueInstance 采用volatile关键字修饰也是很也必要的。


uniqueInstance=new SingLeton();这段代码其实是分为三步执行。


1. 分配内存空间。


2. 初始化对象。


3. 将uniqueInstance指向分配的内存地址。


但是由于JVM具有指令重排的特性,有可能执行顺序变为了1>3>2,这在单线程情况下自然是没有问题的,但是如果是多线程就有可能B线程获得是一个还没有初始化的对象以致于程序出错。


使用使用volatile修饰,目的是禁止JVM的指令重排,保证在多线程环境下也能正常运行。


            

本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注编程语言JAVA频道!

本文由 @小标 发布于职坐标。未经许可,禁止转载。
喜欢 | 1 不喜欢 | 0
看完这篇文章有何感觉?已经有1人表态,100%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式AI+学习就业服务平台 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved