Java 中的双重检查(Double-Check)

转载自    Java 中的双重检查(Double-Check)

在 Effecitve Java 一书的第 48 条中提到了双重检查模式,并指出这种模式在 Java 中通常并不适用。该模式的结构如下所示:

public Resource getResource() {  if (resource == null) {   synchronized(this){   if (resource==null) {  resource = new Resource();    }     }    }  return resource;  
}  

该模式是对下面的代码改进:

public synchronized Resource getResource(){  if (resource == null){   resource = new Resource();    }  return resource;  
}  

这段代码的目的是对 resource 延迟初始化。但是每次访问的时候都需要同步。为了减少同步的开销,于是有了双重检查模式。

在 Java 中双重检查模式无效的原因是在不同步的情况下引用类型不是线程安全的。对于除了 long 和 double 的基本类型,双重检查模式是适用 的。比如下面这段代码就是正确的:

private int count;  
public int getCount(){  if (count == 0){   synchronized(this){   if (count == 0){  count = computeCount();  //一个耗时的计算  }     }    }  return count;  
}  

上面就是关于java中双重检查模式(double-check idiom)的一般结论。但是事情还没有结束,因为java的内存模式也在改进中。Doug Lea 在他的文章中写道:“根据最新的 JSR133 的 Java 内存模型,如果将引用类型声明为 volatile,双重检查模式就可以工作了”,参见 http://gee.cs.oswego.edu/dl/cpj/updates.html 。

所以以后要在 Java 中使用双重检查模式,可以使用下面的代码:

private volatile Resource resource;  
public Resource getResource(){  if (resource == null){   synchronized(this){   if (resource==null){  resource = new Resource();    }     }    }  return resource;  
}  
当然了,得是在遵循 JSR133 规范的 Java 中。


所以,double-check 在 J2SE 1.4 或早期版本在多线程或者 JVM 调优时由于 out-of-order writes,是不可用的。 这个问题在 J2SE 5.0 中已经被修复,可以使用 volatile 关键字来保证多线程下的单例。
public class Singleton {  private volatile Singleton instance = null;  public Singleton getInstance() {  if (instance == null) {  synchronized(this) {  if (instance == null) {  instance = new Singleton();  }  }  }  return instance;  }  
}  

推荐方法 是Initialization on Demand Holder(IODH),

详见 http://en.wikipedia.org/wiki/Initialization_on_demand_holder_idiom

public class Singleton {  static class SingletonHolder {  static Singleton instance = new Singleton();  }  public static Singleton getInstance(){  return SingletonHolder.instance;  }  
}  




本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/329141.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用 Autofac 进行依赖注入

先说下为什么翻译这篇文章,既定的方向是架构,然后为了学习架构就去学习一些架构模式、设计思想。 突然有一天发现依赖注入这种技能。为了使得架构可测试、易维护、可扩展,需要架构设计为松耦合类型,简单的说也就是解耦。为了解耦前…

组合的示例代码 java_java实现Composite组合模式的实例代码

//20210121写在前面:刚期末考试完,考了面向对象,里边儿有23个设计模式,我寻思着考完挨个儿实现一下,本文实现组合模式组合模式核心思想类似文件夹的概念,构件树形结构,树形有叶子结点和文件夹结…

Java中的ThreadPoolExecutor类

转载自 Java中的ThreadPoolExecutor类在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了&…

webpack 前端构建

一、建立简单的项目目录 1、创建 manager 根目录(作为项目根目录)2、执行 npm init,在根目录manager下自动生成 package.json文件3、npm install webpack --save-dev,在项目中安装 webpack npm包4、在根目录下 创建 webpack.config.js,所有的…

简析 .NET Core 构成体系

简析 .NET Core 构成体系Roslyn 编译器RyuJIT 编译器CoreCLR & CoreRTCoreFX(.NET Core Libraries).NET Core 代码开发、部署、运行过程总结 前文介绍了.NET Core 在整个.NET 平台所处的地位,以及与.NET Framework的关系(原文链接),本文将详细介绍.N…

判断一个男人穷还是富,只看这几点!

转载至: 来源:甜蜜爸妈手记(wxtm01) 作者:甜甜妈 创业君 导读 千主意万主意,如果不行动,永远就只是个想法而已。好想法要配得上行动才行。 看看他的爱好一个有事业心男人,绝对不…

php制作留言板的题_PHP实现留言板功能实例代码

本文实例为大家分享了php留言板的实现思路,供大家参考,具体内容如下:1.创建一个存放留言信息的文件名2.获取表单中的数据给一个变量3.判断文件的时候存在4.对文件执行写的操作,在这之前,注意打开文件的时候&#xff0c…

Java线程池,从使用到原理

转载自 Java线程池,从使用到原理线程池的技术背景 在面向对象编程中,创建和销毁对象是很费时间的,因为创建一个对象要获取内存资源或者其它更多资源。在Java中更是如此,虚拟机将试图跟踪每一个对象,以便能够在对象销毁…

聊聊HTTPS和SSL/TLS协议

要说清楚 HTTPS 协议的实现原理,至少需要如下几个背景知识。1. 大致了解几个基本术语(HTTPS、SSL、TLS)的含义2. 大致了解 HTTP 和 TCP 的关系(尤其是“短连接”VS“长连接”)3. 大致了解加密算法的概念(尤…

php事件编程,PHP相应button中onclick事件的案例分析

PHP相应button中onclick事件的案例分析发布时间:2020-11-10 11:28:31来源:亿速云阅读:71作者:小新小编给大家分享一下PHP相应button中onclick事件的案例分析,相信大部分人都还不怎么了解,因此分享这篇文章给…

Java 中Timer和TimerTask 定时器和定时任务使用的例子

转载自 Java 中Timer和TimerTask 定时器和定时任务使用的例子 这两个类使用起来非常方便,可以完成我们对定时器的绝大多数需求 Timer类是用来执行任务的类,它接受一个TimerTask做参数 Timer有两种执行任务的模式,最常用的是schedule,它可以以两种方式执…

复制一个5G文件只需要两秒,全网最牛方法!

文章来至 微信公众号:中国黑客联盟 很多时候我们在复制比较大的文件的时候是一件多么痛苦的事情,因为少的几分钟多则十几分钟,这样的等待是我们无法容忍的!那么今天我们就教大家如何快速的复制电脑大文件! 首先我…

.NET Core也可以使用MongoDB了

可能是由于.NET Core还不是正式版的缘故吧,MongoDB的官方Driver(http://mongodb.github.io/mongo-csharp-driver/)一直不支持.NET Core,这给想在.NET Core上尝试MongoDB带来了不便,本人就是其中之一 :) 于是Fork了官方…

Java多线程系列--“JUC线程池”06之 Callable和Future

转载自 Java多线程系列--“JUC线程池”06之 Callable和FutureCallable 和 Future 简介Callable 和 Future 是比较有趣的一对组合。当我们需要获取线程的执行结果时,就需要用到它们。Callable用于产生结果,Future用于获取结果。 1. Callable Callable 是…

php array分组,php数组分组简单例子

在php网站开发过程中有时候需要把结果集进行分组,使用php的内置函数array_chunk就可以实现 代码如下复制代码$teamsarray(1,2,3,4,5,6,7,8,9);$teamsarray_chunk($teams,2);print_r($teams);/*Array([0] > Array([0] > 1[1] > 2)[1] > Array([0] > 3…

SuperSocket源码解析之开篇

一 简介 官方介绍:SuperSocket 是一个轻量级, 跨平台而且可扩展的 .Net/Mono Socket 服务器程序框架。你无须了解如何使用 Socket, 如何维护 Socket 连接和 Socket 如何工作,但是你却可以使用 SuperSocket 很容易的开发出一款 Socket 服务器端软件&#…

Java守护线程概述

转载自 Java守护线程概述Java的线程分为两种:User Thread(用户线程)、DaemonThread(守护线程)。 只要当前JVM实例中尚存任何一个非守护线程没有结束,守护线程就全部工作;只有当最后一个非守护线程结束是,守护线程随着JVM一同结束…

php while循环次数,php while循环得到循环次数

php while循环得到循环次数复制代码 代码如下:$link mysql_connect(localhost,root,pwd);mysql_select_db(db);$sql "select region_id,local_name from regions where region_grade1";$result mysql_query($sql);$i 0;while ($row mysql_fetch_assoc($result)) {…

EntityFramework和EntityFramework.Extended使用说明——性能,语法和产生的sql

环境说明:EntityFramework 6.1.3和.Net Framework4.5性能注意事项:https://msdn.microsoft.com/zh-cn/library/cc853327.aspx比较精髓的一点:查询执行的各个阶段中的准备查询,每个唯一查询一次。包括编写查询命令、基于模型和映射元数据生成命令树和定义所返回数据的形状的成本…

三个水桶(看了三遍,想了五遍!)

转载至:微信公众号: 创业励志网 一 有位木匠砍了一树,把它做了三个木桶。 一个装粪,就叫粪桶,众人躲着; 一个装水,就叫水桶,众人用着; 一个装酒,就叫酒桶&…