文档章节

单例模式之懒汉式与饿汉式

o
 osc_g8254g7s
发布于 2019/08/19 20:23
字数 1196
阅读 5
收藏 0

懒汉式单例

package single;

public class Monitor {
//开始没有班长,用静态属性表示
private static Monitor monitor=null;
//构造方法私有化,防止出现多个班长对象
private Monitor(){};
public static Monitor getmonitor(){
if(monitor==null){
monitor=new Monitor();
}
return monitor;
}
}
  1. 首先班里没有班长,用静态属性表示.

  2. 将班长类中的班长属性私有化,防止在其他地方实例化,出现多个班长对象.

  3. 定义一个获取班长的方法,没有就new一个,有的话就返回已有对象.

 

以上代码看起来逻辑正确,但是学习过多线程就能够知道,该类存在线程安全问题.

现在有线程A,B,全部在monitor=null的情况下进入方法体中,这样就会有两个班长对象产生,显然是不对的,那么我们让代码更新一下

package single;

public class Monitor {
//开始没有班长,用静态属性表示
private static Monitor monitor=null;
//构造方法私有化,防止出现多个班长对象
private Monitor(){};
public static synchronized Monitor getmonitor(){
if(monitor==null){
monitor=new Monitor();
}
return monitor;
}
}

这样线程安全解决了,但是当多线程全部执行至getmonitor方法时,明显会有多余的等待时间,这样代码执行效率会变低,那么我们再把代码结构优化一下

public class Monitor {
// 开始没有班长,用静态属性表示
private static Monitor monitor = null;

// 构造方法私有化,防止出现多个班长对象
private Monitor() {
};

public static Monitor getmonitor() {
if (monitor == null) {
           //如果没有班长让所有线程进来竞争
synchronized (Monitor.class) {
if (monitor == null)
           //当产生了班长后后面的线程将不会执行循环体
              {
monitor = new Monitor();
}
}
}
       
return monitor;
}
}

这样就明确很多了,这就是所谓的懒汉模式.懒汉模式就是当我们需要的时候,我们就去new对象,但是查询相关资料,我们发现还存在一些问题.

在 monitor = new Monitor();,在这个操作中,JVM主要干了三件事:

1、在堆空间里分配一部分空间;

2、执行 Monitor 的构造方法进行初始化;

3、把 monitor 对象指向在堆空间里分配好的空间。

把第3步执行完,这个 monitor 对象就已经不为空了。

但是,当我们编译的时候,编译器在生成汇编代码的时候会对流程顺序进行优化。优化的结果不是我们可以控制的,有可能是按照1、2、3的顺序执行,也有可能按照1、3、2的顺序执行。

如果是按照1、3、2的顺序执行,恰巧在执行到3的时候(还没执行2),突然跑来了一个线程,进来 getMonitor ()方法之后判断 monitor 不为空就返回了 monitor 实例。此时 monitor 实例虽不为空,但它还没执行构造方法进行初始化(即没有执行2),所以该线程如果对那些需要初始化的参数进行操作那就悲剧了。但是加了 volatile 关键字的话,就不会出现这个问题。这是由 volatitle 本身的特性决定的。

即我们的最终代码为

public class Monitor {
// 开始没有班长,用静态属性表示
private static Monitor monitor = null;

// 构造方法私有化,防止出现多个班长对象
private Monitor() {
};

public static volatitle Monitor getmonitor() {
if (monitor == null) {
           //如果没有班长让所有线程进来竞争
synchronized (Monitor.class) {
if (monitor == null)
           //当产生了班长后后面的线程将不会执行循环体
              {
monitor = new Monitor();
}
}
}
return monitor;
}
}

 

饿汉式单例

package single;

public class Monitor1 {
private Monitor1 (){}
//创建Monitor1的无参构造器
private static Monitor1 monitor=new Monitor1();
//先创建Monitor1对象
//待有需求的时候再调用
public static Monitor1 getMonitor(){
return monitor;
}
}

 

前面提到单例模式的懒汉式,上文就是恶汉式的单例,旨在先把需要的对象先创建好,待有需求的时候直接调用,相对来说线程安全而且方便.

那么饿汉式如此简单粗暴且线程安全,是不是就没有懒汉式的事情了呢?显然不是的,存在即有其合理性.很明显两者最大的区别在于,懒汉式是在有需求的时候new 对象,饿汉式是提前准备对象,不管用不用.

那么试想有这么一个场景,当提前准备了很多对象,但是又不知道什么时候调用,而且这时候突然有临时需求,对对象有要求,那么势必有一部分对象是不符合条件的,这样既浪费了内存空间,对实际应用也产生了不佳的影响.因此两者模式都有其适用的范围.

o
粉丝 0
博文 500
码字总数 0
作品 0
私信 提问
加载中
请先登录后再评论。

暂无文章

pycurl libcurl link-time ssl backend (nss)

pip uninstall pycurlecho 'pycurl==7.19.5.1 --global-option="--with-nss"' > requires.pypip install -r requires.py...

小红手
28分钟前
17
0
计算机网络性能衡量

1、速率 单位时间(s)内传输信息(bit)量 单位:KB/s, MB/s, Gb/s K = 10^3 ,M = 10^6, G=10^9 一般表示的是理想的传输速率 2、带宽 计算机网络中的带宽和通信等领域的带宽概念不一样,计算机网...

osc_np3y0rbq
28分钟前
3
0
互联网掀起农家乐,巨头上演AI掘金战

配图来自Canva **前有网易、阿里AI养猪,后有腾讯AI养鹅,互联网大佬们纷纷玩起了“农家乐”,互联网的生意在尖端技术的引领之下频频跨界,巨头之间的较量也从线上延伸至线下。**自古“民以食...

osc_5cok9i01
29分钟前
9
0
原来!我在4年前就开始体验雾游戏了!

前有云游戏后有雾游戏,游戏的方式看来起来越来越多种多样。那么“震撼业界”的雾游戏到底是什么来头?它依靠什么改变游戏界?它的原理又是什么? 本月月初,著名的日本游戏杂志《Fami通》表...

osc_j34n26zn
31分钟前
11
0
活动预告|田溯宁与你相约GSMA Thrive·万物生晖,分享5G风口下的创新与投资洞察

在万物互联的时代背景下,5G+AI+IoT的技术变革与融合,正在引发一场深刻的全产业创新与变革。5G技术创新、行业应用及投资机遇已成为科技行业所瞩目的焦点。 6月30日,宽带资本董事长田溯宁将...

osc_0qnrwmy3
32分钟前
7
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部