当前位置: 首页 > 面试题库 >

Java并发中“程序顺序规则”的解释

赖浩荡
2023-03-14
问题内容

程序顺序规则指出:“线程中的每个动作都发生在该线程中的每个动作之后,程序顺序之后”

我在另一个线程中读到一个 动作

  • 读取和写入变量
  • 显示器的锁定和解锁
  • 用线程开始和加入

这是否意味着可以按顺序更改读取和写入,但不能通过第二行或第三行中指定的操作更改读取和写入操作的顺序?

2.“程序顺序”是什么意思?

举例说明将非常有帮助。

其他相关问题

假设我有以下代码:

long tick = System.nanoTime(); //Line1: Note the time
//Block1: some code whose time I wish to measure goes here
long tock = System.nanoTime(); //Line2: Note the time

首先,它是一个单线程应用程序,可以使事情保持简单。编译器注意到它需要检查时间两次,并且还注意到一个代码块与周围的时间标记行没有依赖关系,因此它看到了重新组织代码的潜力,这可能导致Block1没有被定时调用所包围。在实际执行期间(例如,考虑此顺序Line1->
Line2->
Block1)。但是,作为程序员,我可以看到Line1,2和Block1之间的依赖关系。Line1应该紧接在Block1之前,Block1需要有限的时间才能完成,而Line2紧随其后。

所以我的问题是:我是否正确地测量块?

  • 如果是,则阻止编译器重新排列顺序。
  • 如果没有,(经过Enno的回答后认为是正确的),我可以采取什么措施来防止它。

PS:我从最近在SO中问到的另一个问题中窃取了此代码。


问题答案:

它可能有助于解释为什么首先存在这样的规则。

Java是一种过程语言。即,您告诉Java如何为您做某事。如果Java不按照您编写的顺序执行您的指令,则显然无法正常工作。例如,在下面的html" target="_blank">示例中,如果Java执行2->
1-> 3,则炖汤将被破坏。

1. Take lid off
2. Pour salt in
3. Cook for 3 hours

那么,为什么规则不简单地说“ Java按照您编写的顺序执行您编写的内容”?简而言之,因为Java很聪明。请看以下示例:

1. Take eggs out of the freezer
2. Take lid off
3. Take milk out of the freezer
4. Pour egg and milk in
5. Cook for 3 hours

如果Java像我一样,它将按顺序执行它。但是Java很聪明,足以理解它更有效,而且如果执行1-> 3-> 2-> 4->
5(如果您不必再走到冷冻室,并且不会改变配方)。

因此,规则“线程中的每个动作发生在该线程中的每个动作在程序顺序之后发生之前”是要说的:“在单个线程中,您的程序将 在完全执行中 一样
运行您编写的顺序我们可能会更改幕后的顺序,但要确保这些顺序都不会改变输出。

到目前为止,一切都很好。为什么它在多个线程中不一样?在多线程编程中,Java不够聪明,无法自动执行。它将用于某些操作(例如,连接线程,启动线程,何时使用锁(监视器)等),但对于其他内容,则需要明确告诉它不要进行重新排序,否则会更改程序输出(例如volatile,字段上的标记,使用锁等)。

注意:
有关“先于关系”的快速附录。这是一种奇妙的说法,无论重新排序Java可能做什么,物料A都会在物料B之前发生。在我们后来出现的怪异例子中,“步骤1和3
发生在 步骤4“将鸡蛋和牛奶倒入”之前”。又例如,“步骤1和3不需要 事前发生的 关系,因为它们不以任何方式相互依赖”

关于其他问题和对评论的回应

首先,让我们确定“时间”在编程世界中的含义。在编程中,我们有“绝对时间”的概念(现在世界上的时间是什么?)和“相对时间”的概念(自x以来已经过去了多少时间?)。在理想的世界中,时间就是时间,但是除非我们内置了原子钟,否则绝对时间必须随时校正。另一方面,相对时间我们不希望进行更正,因为我们只对事件之间的差异感兴趣。

在Java中,System.currentTime()处理绝对时间并System.nanoTime()处理相对时间。这就是为什么nanoTime的Javadoc指出“此方法
只能用于测量经过的时间, 并且与系统或挂钟时间的任何其他概念无关”。

实际上,currentTimeMillis和nanoTime都是本机调用,因此编译器无法实际证明重新排序是否会影响正确性,这意味着它将不会对执行进行重新排序。

但是让我们想象一下,我们想编写一个编译器实现,它实际上可以查看本机代码并在合法的情况下对所有内容进行重新排序。当我们查看JLS时,它只告诉我们:“只要无法检测到任何东西,您都可以对其重新排序”。现在,作为编译器作者,我们必须确定重新排序是否会违反语义。对于相对时间(nanoTime),如果我们对执行重新排序,则显然是无用的(即违反了语义)。现在,如果我们重新排序绝对时间(currentTimeMillis),会违反语义吗?只要我们可以将世界时间的来源(例如系统时钟)与我们决定的任何时间(例如“
50ms”)*之间的时差限制为零,我就说不。对于以下示例:

long tick = System.currentTimeMillis();
result = compute();
long tock = System.currentTimeMillis();
print(result + ":" + tick - tock);

如果编译器可以证明它compute()花费的时间少于我们允许的最大系统时钟偏差,则按以下方式重新排序是合法的:

long tick = System.currentTimeMillis();
long tock = System.currentTimeMillis();
result = compute();
print(result + ":" + tick - tock);

由于这样做不会违反我们定义的规范,因此也不会违反语义。

您还询问为什么JLS中不包含此内容。我认为答案将是“保持JLS简短”。但是我对此领域了解不多,因此您可能要为此提出一个单独的问题。

*:在实际的实现中,此差异取决于平台。



 类似资料:
  • 问题内容: 我正在阅读一些Java文本,并获得以下代码: 在本文中,作者没有给出明确的解释,最后一行的效果是: ; 我不确定自己是否理解:评估是如何发生的? 问题答案: 让我说得很清楚,因为人们一直误会这一点: 子表达式的求值顺序与关联性和优先级无关。结合性和优先级确定以什么顺序运营商执行,但不以什么顺序确定的子表达式进行评估。你的问题与子表达式的计算顺序有关。 考虑一下。乘法比加法具有更高的优先

  • null 我在上面试图指出的是,只有在执行第一个规则时,第二个规则才会执行。但是,正如我所理解的,规则的“如果”部分是在“然后”部分之前执行的,因此,第二条规则失败了。

  • 我正在开发一些关于guvnor插件的规则。e、 g.检查 这个人就是老师。 老师是男性。 男教师为45岁或以上。 我把这三条规则分开处理。但现在我想按顺序调用它们。 比如这个人是老师。插入新的事实男性教师。然后在下一个规则中,在收到的事实中填充教师的年龄。然后检查教师的年龄。 那么我如何在drools-guvnor插件中实现这一点。 我在drools-guvnor5.5插件jboss中使用引导编辑

  • 我做了一个自定义验证规则,它迭代一个包含键

  • 我有这样的情况,在规则文件中的所有规则必须检查执行。如果我的理解是正确的,文档所说的规则将由引擎任意执行。 我有一个或多个疑问。 > 我在许多地方得到了答案,我必须使用显著性功能来按顺序执行它们。如果我使用显著性,并且我有执行所有规则的要求,它真的会大规模地影响性能吗?如果是,它会如何影响性能,甚至规则引擎也会任意执行所有规则,比如一些随机顺序。 提前谢谢。

  • 名称设置方法 京东小程序的名称可以由中英文、数字及下划线组成,长度在4-30个字符之间。 京东小程序的名称是唯一的,不可以与其他小程序名称重复。经过检测保证唯一性才可应用。 名称修改方法 修改方法:登录【京东小程序】-> 【我的小程序】中的【查看】->【设置】->【基础设置】->【小程序名称】->【修改】,当修改名称命中保护词的时候,需要进一步审核通过方可修改成功,名称修改成功后,原名称会立即释放