java单例模式是什么意思,JAVA单例模式

  java单例模式是什么意思,JAVA单例模式

  前言

  本文来自我的微信官方账号。如果没看过,直接看就好了。如果你读过,你可以再读一遍。我稍微修改了一些内容。今天的解释如下:

  一、什么是单例模式

  【singleton pattern】,英文名:Singleton Pattern,这种模式非常简单,一个类型只需要一个实例,是属于创建类型的常见软件设计模式。singleton pattern的方法创建的类在当前进程中只有一个实例(如果需要,也可能属于一个线程中的单个实例,例如,在线程上下文中只使用同一个实例)。

  (推荐视频:java视频教程

  我们大概知道,其实说白了,整个项目周期只会有一个实例。当项目停止时,实例将被销毁,当它重新启动时,我们的实例将再次产生。

  上面的文章里提到了一个名词【创造型】的设计模式。创作型的设计模式是什么?

  创建型(Creational)模式:负责对象创建,我们使用这个模式,就是为了创建我们需要的对象实例的。

  除了创造性的模式,还有两种其他类型的模式:

  这两种设计模式将在后面讨论。这里,先按“不看”键。

  让我们关注如何从0创建singleton模式的对象实例。

  二、如何创建单例模式

  实现单例模式的方法有很多:从“懒汉式”到“饿汉式”,最后“双检锁”模式,。这里我们将一步一步地解释如何创建单例。

  1、正常的思维逻辑顺序

  因为我们想要创建一个单一的实例,我们首先需要学习如何创建一个实例。这个很简单。我相信每个人都会创建一个实例,就像这样:

  ///摘要

  ///定义天气类

  ////摘要

  公共类天气预报

  {

  公共天气预报()

  {

  日期=日期时间。现在;

  }

  公共日期时间日期{ get设置;}

  公共int TemperatureC { get设置;}

  public int temperature ef=32(int)(temperature c/0.5556);

  公共字符串摘要{ get设置;}

  }

  [HttpGet]

  公共天气预报获取()

  {

  //实例化一个对象实例

  WeatherForecast天气=new weather forecast();

  返程天气;

  }我们每次访问,时间都会发生变化,所以我们的实例总是在创建和变化:

  相信大家都能看出来这个代码是什么意思。话不多说,直接下去。我们知道单例模式的核心目的是:

  必须保证这个实例在整个系统的运行周期内是唯一的,这样可以保证中间不会出现问题。

  好吧,让我们改进它。我们不是说要唯一的吗?说吧!为什么我不回去呢?

  ///摘要

  ///定义天气类

  ////摘要

  公共类天气预报

  {

  //定义一个静态变量来保存该类的唯一实例

  私有静态天气预报uniqueInstance

  //定义一个私有构造函数,让外界无法创建这个类的实例。

  私人天气预报()

  {

  日期=日期时间。现在;

  }

  ///摘要

  ///静态方法,以返回唯一实例

  ///如果存在,则返回

  ////摘要

  ///返回/返回

  公共静态天气预报GetInstance()

  {

  //如果该类的实例不存在,则创建一个,否则直接返回

  //其实严格来说这不属于[singleton]

  if (uniqueInstance==null)

  {

  unique instance=new weather forecast();

  }

  返回uniqueInstance

  }

  公共日期时间日期{ get设置;} public int TemperatureC { get设置;}

  public int temperature ef=32(int)(temperature c/0.5556);

  公共字符串摘要{ get设置;}

  }然后我们修改调用方法,因为我们的默认构造函数已经私有化,不允许再创建实例,所以我们就这样调用它:

  [HttpGet]

  公共天气预报获取()

  {

  //实例化一个对象实例

  天气预报天气=天气预报。GetInstance();

  返程天气;

  }最后,我们来看看效果:

  这时,我们可以看到时间没有改变,也就是说,我们的实例是唯一的,我们完成了!你很开心吗?

  但是,不用担心,问题来了。我们目前是单线程的,所以只有一个。多线程呢?如果多个线程同时访问,也会正常吗?

  我们在这里做个测试。当项目启动时,我们使用多线程来调用它:

  [HttpGet]

  公共天气预报获取()

  {

  //实例化一个对象实例

  //WeatherForecast天气=天气预报。GetInstance();

  //要调用的多线程

  for(int I=0;i3;我)

  {

  var th=新线程(

  新的parameterized threadstart((state)=1

  {

  天气预报。GetInstance();

  })

  );

  th。开始(一);

  }

  返回null

  }那我们来看看效果如何。按照我们的思路,应该是构造者只会走一次,其实不是:

  三个线程第一次访问GetInstance方法时,同时判断(uniqueInstance==null)这个条件时都返回true,然后都创建实例。这肯定是不对的。那我们能做什么?只要让GetInstance方法只运行一个线程,我们就可以加一个锁来控制它。代码如下:

  公共类天气预报

  {

  //定义一个静态变量来保存该类的唯一实例

  私有静态天气预报uniqueInstance

  //定义一个锁来防止多线程

  私有静态只读对象locker=new object();

  //定义一个私有构造函数,让外界无法创建这个类的实例。

  私人天气预报()

  {

  日期=日期时间。现在;

  }

  ///摘要

  ///静态方法,以返回唯一实例

  ///如果存在,则返回

  ////摘要

  ///返回/返回

  公共静态天气预报GetInstance()

  {

  //当第一个线程执行时,它将“锁定”locker对象,

  //其他线程执行时,会等待locker完成解锁。

  锁(储物柜)

  {

  //如果该类的实例不存在,则创建一个,否则直接返回

  if (uniqueInstance==null)

  {

  unique instance=new weather forecast();

  }

  }

  返回uniqueInstance

  }

  公共日期时间日期{ get设置;}

  公共int TemperatureC { get设置;}

  public int temperature ef=32(int)(temperature c/0.5556);

  公共字符串摘要{ get设置;}

  }这时我们进行并发测试,发现都是一样的,从而达到了想要的效果。但这真的是最完美的吗?其实不是的。因为我们锁了锁,所以只判断第一次是不是空的。如果锁被创建,我们以后就不用担心它了。我们只关心uniqueInstance是否为空。那么让我们完善它:

  ///摘要

  ///定义天气类

  ////摘要

  公共类天气预报

  {

  //定义一个静态变量来保存该类的唯一实例

  私有静态天气预报uniqueInstance

  //定义一个锁来防止多线程

  私有静态只读对象locker=new object();

  //定义一个私有构造函数,让外界无法创建这个类的实例。

  私人天气预报()

  {

  日期=日期时间。现在;

  }

  ///摘要

  ///静态方法,以返回唯一实例

  ///如果存在,则返回

  ////摘要

  ///返回/返回

  公共静态天气预报GetInstance()

  {

  //当第一个线程执行时,它将“锁定”locker对象,

  //其他线程执行时,会等待locker完成解锁。

  if (uniqueInstance==null)

  {

  锁(储物柜)

  {

  //如果该类的实例不存在,则创建一个,否则直接返回

  if (uniqueInstance==null)

  {

  unique instance=new weather forecast();

  }

  }

  }

  返回uniqueInstance

  }

  公共日期时间日期{ get设置;}

  公共int TemperatureC { get设置;}

  public int temperature ef=32(int)(temperature c/0.5556);

  公共字符串摘要{ get设置;}

  }只有这样,我们才能最终完美地实现我们的单例模式!完成了。

  2、幽灵事件:指令重排

  当然,如果你看完了以上四个步骤,就已经可以开始了。通常,这是我们使用和思考的,但它真的是万无一失的。有个JAVA朋友提了这个问题,C#里没听说过。我无知吗:

  单例模式的幽灵事件,时令重排会偶尔导致单例模式失效。

  是不是听起来很高大上,很迷茫?没关系。我们通常不使用它,但我们可以理解:

  这是从网上摘录的。只看大概意思。理解双止锁失效的原因有两个关键点。

  1.编译器的写重排问题。

  例:B B=new B();

  上面这句话不是原子操作。一部分是新建一个B对象,一部分是将新对象赋给B .

  直观上,我们可能认为我们先构造对象,然后赋值。可惜这个顺序不固定。在编译器的重排下,可能会出现先赋值再构造对象的情况。

  2.结合上下文和使用场景。

  在了解了1中写操作的重排后,我卡住了,因为我真的不知道这个重排会有什么影响。其实是因为我看代码不够仔细,没有意识到使用场景。双重检查锁的一个常见使用场景是在singleton模式下初始化一个singleton并返回,然后在初始化方法的方法体中使用初始化的singleton对象。

  三、Singleton = 单例 ?

  上面说了很多,也介绍了Singleton的原理和步骤。那么问题来了。当我们在学习依赖注入的时候,Singleton singleton注入和上面说的用的是一个东西吗?这里,我们直接用多线程测试一下:

  ///摘要

  ///定义一个情绪类

  ////摘要

  公众阶级感觉

  {

  公众感受()

  {

  日期=日期时间。现在;

  }

  公共日期时间日期{ get设置;}

  }

  //单个实例注册到容器中。

  服务。AddSingletonFeeling();然后我们将服务注入控制器,然后进行多线程测试:

  private readonly ILoggerWeatherForecastController _ logger;

  私人只读Feeling _ feeling

  公共WeatherForecastController(ILoggerWeatherForecastController记录器,感觉感觉)

  {

  _ logger=logger

  _feeling=感觉;

  }

  [HttpGet]

  公共天气预报获取()

  {

  //实例化一个对象实例

  //WeatherForecast天气=天气预报。GetInstance();

  //要调用的多线程

  for(int I=0;i3;我)

  {

  var th=新线程(

  新的parameterized threadstart((state)=1

  {

  //天气预报。GetInstance();

  //此刻的心情

  控制台。WriteLine(_感觉。日期);

  })

  );

  th。开始(一);

  }

  返回null

  }测试的结果,合理,我们项目初始化服务的时候只进了一次构造函数:

  和我们上面说的一样,Singleton是一种单例,也是双检锁类型,因为结论表明,我们使用singleton模式时,可以直接使用依赖注入Sigleton来满足,非常方便。

  四、单例模式的优缺点

  单例模式的[卓越]优势:

  (1)保证唯一性:防止其他对象实例化,保证实例的唯一性;

  (2)整体:数据定义后,当前实例和数据可以在整个项目的任何地方使用;

  [不好],单例模式的缺点:

  (1)内存常驻:由于单个实例的生命周期最长,存在于整个开发系统中,如果一直添加数据或者常驻,会造成一定的内存消耗。

  以下内容来自百度百科:

  本文来自我们,java教程专栏,欢迎学习!这就是java Singleton模式和Singleton的细节。更多请关注我们的其他相关文章!

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: