ajax 示例

我们已经花了几个月的时间来稳定Plumbr中的锁定检测功能 。 在此期间,我们遇到了许多棘手的并发问题。 许多问题是独特的,但是一种特殊类型的问题一直反复出现。

您可能已经猜到了–滥用volatile关键字。 我们已经发现并解决了许多问题,其中大量使用volatile使应用程序的任意部分变慢,延长了锁定保持时间,最终使JVM屈服。 反之亦然-授予过于宽松的访问策略会引发一些令人讨厌的并发问题。

我想每个Java开发人员都会回想起该语言的第一步。 使用手册和教程的日子和日子。 这些教程都有关键字列表,其中volatile是最可怕的关键字之一。 随着时间的流逝,越来越多的代码不需要使用此关键字,我们很多人都忘记了volatile的存在。 直到生产系统开始以无法预测的方式破坏数据或死亡。 调试这种情况迫使我们中的一些人真正理解了这个概念。 但是我敢打赌,这并不是一个令人愉快的课程,因此也许我可以通过一个简单的例子来阐明一些概念,从而节省一些时间。

挥发作用的例子

该示例模拟了一个银行办公室。 银行办公室的类型,您可以在该办公室中从售票机中选择队列编号,然后在您前面的队列得到处理后等待邀请。 为了模拟这样的办公室,我们创建了以下示例,该示例由两个线程组成。

这两个线程中的第一个被实现为CustomerInLine。 这是一个线程,除了等待NEXT_IN_LINE中的值与客户的票证匹配外,什么也不做。 票号被硬编码为#4。 时间到时( NEXT_IN_LINE> = 4),线程宣布等待已结束并结束。 这模拟了有一些客户在排队的到达办公室的客户。

排队实现在Queue类中,该类运行一个循环,该循环调用下一个客户,然后通过为每个客户Hibernate200ms来模拟与该客户的工作。 呼叫下一个客户后,存储在类变量NEXT_IN_LINE中的值将增加1。

public class Volatility {static int NEXT_IN_LINE = 0;public static void main(String[] args) throws Exception {new CustomerInLine().start();new Queue().start();}static class CustomerInLine extends Thread {@Overridepublic void run() {while (true) {if (NEXT_IN_LINE >= 4) {break;}}System.out.format("Great, finally #%d was called, now it is my turn\n",NEXT_IN_LINE);}}static class Queue extends Thread {@Overridepublic void run() {while (NEXT_IN_LINE < 11) {System.out.format("Calling for the customer #%d\n", NEXT_IN_LINE++);try {Thread.sleep(200);} catch (InterruptedException e) {e.printStackTrace();}}}}
}

因此,运行此简单程序时,您可能希望该程序的输出类似于以下内容:

Calling for the customer #1
Calling for the customer #2
Calling for the customer #3
Calling for the customer #4
Great, finally #4 was called, now it is my turn
Calling for the customer #5
Calling for the customer #6
Calling for the customer #7
Calling for the customer #8
Calling for the customer #9
Calling for the customer #10

看来,这个假设是错误的。 取而代之的是,您将看到通过10个客户的列表进行的队列处理,并且不幸的线程模拟了4号客户,从不提醒它已经看到邀请。 发生了什么,为什么客户仍然坐在那里无休止地等待着呢?

分析结果

您在此处面临的是将JIT优化应用于代码,该代码将对NEXT_IN_LINE变量的访问进行缓存。 两个线程都有自己的本地副本,并且CustomerInLine线程从不看到Queue实际增加了线程的值。 如果现在您认为这是JVM中的一种可怕的错误,那么您就不完全正确了-允许编译器这样做以避免每次都重新读取该值。 因此,您可以提高性能,但要付出代价–如果其他线程更改状态,则缓存副本的线程将不知道该状态,并使用过时的值进行操作。

对于volatile正是这种情况。 有了此关键字,编译器将被警告特定状态是易失的,并且每次执行循环时,代码都被强制重新读取该值。 有了这些知识,我们就可以进行简单的修复-只需将NEXT_IN_LINE的声明更改为以下内容,您的客户就不会永远坐在队列中:

static volatile int NEXT_IN_LINE = 0;

对于那些只了解volatile用例而感到满意的人,您将很高兴。 只是要知道附加的成本–当您开始声明所有内容都是易失性时,您正在迫使CPU忽略本地缓存并直接进入主内存,从而减慢了代码的速度并阻塞了内存总线。

引擎盖下易挥发

对于那些希望详细了解该问题的人,请和我在一起。 要查看底层发生了什么,让我们打开调试以查看JIT从字节码生成的汇编代码。 通过指定以下JVM选项可以实现此目的:

-XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly

在启用和禁用volatile的情况下启用这些选项的情况下运行程序,可以为我们提供以下重要见解:

运行不带volatile关键字的代码,表明我们在指令0x00000001085c1c5a上可以比较两个值。 当比较失败时,我们继续从0x00000001085c1c60到0x00000001085c1c66,后者跳回到0x00000001085c1c60,并产生无限循环。

0x00000001085c1c56: mov    0x70(%r10),%r11d0x00000001085c1c5a: cmp    $0x4,%r11d0x00000001085c1c5e: jge    0x00000001085c1c68  ; OopMap{off=64};*if_icmplt; - Volatility$CustomerInLine::run@4 (line 14)0x00000001085c1c60: test   %eax,-0x1c6ac66(%rip)        # 0x0000000106957000;*if_icmplt; - Volatility$CustomerInLine::run@4 (line 14);   {poll}0x00000001085c1c66: jmp    0x00000001085c1c60  ;*getstatic NEXT_IN_LINE; - Volatility$CustomerInLine::run@0 (line 14)0x00000001085c1c68: mov    $0xffffff86,%esi

使用volatile关键字后,我们可以看到在指令0x000000010a5c1c40上我们将值加载到寄存器,在0x000000010a5c1c4a上将其与保护值4进行比较。如果比较失败,则从0x000000010a5c1c4e跳回0x000000010a5c1c40,再次为新的值加载值检查。 这确保了我们将看到NEXT_IN_LINE变量的更改后的值。

0x000000010a5c1c36: data32 nopw 0x0(%rax,%rax,1)0x000000010a5c1c40: mov    0x70(%r10),%r8d    ; OopMap{r10=Oop off=68};*if_icmplt; - Volatility$CustomerInLine::run@4 (line 14)0x000000010a5c1c44: test   %eax,-0x1c1cc4a(%rip)        # 0x00000001089a5000;   {poll}0x000000010a5c1c4a: cmp    $0x4,%r8d0x000000010a5c1c4e: jl     0x000000010a5c1c40  ;*if_icmplt; - Volatility$CustomerInLine::run@4 (line 14)0x000000010a5c1c50: mov    $0x15,%esi

现在,希望说明能使您摆脱几个讨厌的错误。

翻译自: https://www.javacodegeeks.com/2014/08/understanding-volatile-via-example.html

ajax 示例

ajax 示例_通过示例了解挥发相关推荐

  1. python示例_带有示例的Python功能指南

    python示例 Python函数简介 (Introduction to Functions in Python) A function allows you to define a reusable ...

  2. 接口文档示例_在示例中使用Android中的Work Manager

    接口文档示例 在本文中,我们将介绍如何在android中使用工作管理器. 工作管理器是android体系结构组件的一部分,并且可以很好地替代所有先前的调度选项. 其他调度选项,例如JobSchedul ...

  3. spark在服务器运行示例_创建示例HTTPS服务器以获取乐趣和收益

    spark在服务器运行示例 通常,在开发或/和针对真实场景进行测试期间,我们(开发人员)面临着运行成熟的HTTPS服务器的需求,可能同时进行一些模拟. 在JVM平台上,除非您知道适合此工作的正确工具, ...

  4. hibernate示例_通过示例Hibernate–第1部分(删除孤儿)

    hibernate示例 所以我想做一系列的冬眠例子,展示冬眠的各种特征. 在第一部分中,我想展示有关删除孤儿功能及其在故事情节中的使用方式. 因此,让我们开始:) 先决条件 : 为了尝试以下示例,您将 ...

  5. python 示例_带有示例的Python File write()方法

    python 示例 文件write()方法 (File write() Method) write() method is an inbuilt method in Python, it is use ...

  6. lock_sh 示例_带有示例的Python date __str __()方法

    lock_sh 示例 Python date .__ str __()方法 (Python date.__str__() Method) date.__str__() method is used t ...

  7. python 示例_带有示例的Python文件关闭属性

    python 示例 文件关闭属性 (File closed Property) closed Property is an inbuilt property of File object (IO ob ...

  8. python 示例_带有示例的Python date timetuple()方法

    python 示例 Python date.timetuple()方法 (Python date.timetuple() Method) date.timetuple() method is used ...

  9. python 示例_带有示例的Python date isocalendar()方法

    python 示例 Python date.isocalendar()方法 (Python date.isocalendar() Method) date.isocalendar() method i ...

最新文章

  1. windows 2012 nps配置
  2. 百度站长工具进击site结果页面[SITE特型]
  3. clob存base64文件存不进去_Kafka 和 RocketMQ 底层存储之那些你不知道的事
  4. centos8 配置 dns_广电行业DNS、DHCP案例详解
  5. larvel php restful_Laravel教你简单写出专业的RestfulAPI
  6. android系统的发展态势,2020年安卓手机发展的7个趋势,只有延伸,并无革命性的变化...
  7. python websocket django vue_Django资料 Vue实现网页前端实时反馈输出信息
  8. java string 分析_java String 可变性的分析
  9. php 控制器方法,ThinkPhp3.2跨控制器调用方法
  10. 电子设计大赛-信号源类题目分析
  11. 高响应比优先调度算法以及其优缺点
  12. disp语句怎么格式 matlab_matlab输出语句print
  13. 路由器命令级别和用户级别
  14. java计算机毕业设计教务排课系统MyBatis+系统+LW文档+源码+调试部署
  15. python中怎么统计英文字符的个数_python 输入一行字符,分别统计出其中英文字母,空格,数字和其他字符的个数用python代码输入一行字符...
  16. 【学习笔记】Kruskal 重构树(BZOJ3551【ONTAK2010】Peaks加强版)
  17. TypeScript 之 More on Functions
  18. 服务器磁盘IO是什么意思?SATA和固态硬盘的性能差异
  19. 2022.04.10-高宝琪毕设阶段性汇报
  20. 请问肾阴虚吃什么药?饮食注意什么?还有桂附地黄丸是治肾阴虚还是治肾阳虚的?谢谢

热门文章

  1. jzoj3410-[GDOI2014模拟]Tree【最小生成树,贪心】
  2. ssl2331OJ1373-鱼塘钓鱼 之1【纯贪心】
  3. 各种模板(数学数论字符串)
  4. 线段树动态开点区间加区间求和
  5. SpringCloud Greenwich(四)注册中心之eureka、Zuul和 gateway网关配置
  6. Jsoup代码解读之二-DOM相关对象
  7. 今天就唠叨唠叨吧……
  8. JS进行性能测试(计时)
  9. grub shell 错误_使用grub-install修复Grub时出错
  10. 检查异常和非检查异常 有空你去学一下检查异常和非检查异常