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

最后是否会返回“发生”?

钱照
2023-03-14
问题内容

我试图说服自己,该finally子句中采取的操作在函数返回 之前发生
(从内存一致性的角度来看)。从JVM规范,很显然,在一个线程中,程序顺序应该是驱动
之前发生 关系-如果 一个 发生 b 按照程序顺序,然后 前发生 b

但是,我没有看到任何明确说明最终 会在 返回 之前发生的
东西,是吗?或者,编译器是否可以通过某种方式对finally子句进行重新排序,因为它只是在记录日志。

激励示例:我有一个线程从数据库中提取对象,并将其放入ArrayBlockingQueue,而另一个线程将其取出。我有一些try-
finally块活动时间,而我看到的影响的回报后 之前 的日志语句

线程1:

public Batch fetch() {
    try {
        log("fetch()+");
        return queryDatabase();
    }
    finally {
        log("fetch()-");
    }
     ...
    workQueue.put(fetch());

线程2:

log("take()+");
Batch b = workQueue.take();
log("take()-");

令我惊讶的是,它以意外的顺序打印出来。是的,虽然不同线程中的日志记录语句可能会出现乱序,但至少存在20毫秒的时差。

124 ms : take()+
224 ms : fetch()+
244 ms : take()-
254 ms : fetch()-

请注意,这个问题与最终的王牌回报并不完全相同。我不是在问什么将返回,而是关于内存一致性和执行顺序。


问题答案:

@David
Heffernan有正确答案。JLS规范在第14.17节中讨论了return语句的行为(包括return语句如何与finally块交互)。从那里复制(重点是我的):

一个带有Expression的return语句试图将控制权转移到包含它的方法的调用者;Expression的值成为方法调用的值。
更准确地说,执行这样的return语句首先会评估Expression
。如果对表达式的求值由于某种原因而突然完成,则return语句由于该原因而突然完成。如果对Expression的求值正常完成,产生一个值V,则return语句突然完成,原因是返回值为V。如果该表达式的类型为float且不是FP-
strict(§15.4),则该值可以是float值集或float-extended-
exponent值集(第4.2.3节)的元素。如果表达式的类型为double,并且不受FP限制,则该值可以是double值集或double-
expended指数值集的元素。

可以看出,return语句总是突然完成。

前面的描述说的是“试图转移控制权”,而不仅仅是“转移控制权”,因为
如果方法或构造函数中的任何try语句(第14.20节)的try块包含return语句,则这些try语句的所有finally子句都会在控制权转移到方法或构造函数的调用者之前,按从内到外的顺序执行
。finally子句的突然完成可能会破坏由return语句启动的控制权的转移。



 类似资料:
  • null 为了帮助进一步演示案例#2,3,4,下面的代码片段强调了当找不到客户时“可能发生”的几个选项...

  • 可以曾经返回吗? 文档没有提到这是一种可能性,所以我想知道我是否必须在取消引用之前检查的结果是否为值。

  • 问题内容: 如果我运行查询,例如: 即使查询与任何记录都不匹配,它也会始终返回结果吗?还是我需要验证并确保结果返回一行? 问题答案: 是的,因为它是一个聚合并且返回零。除非您添加GROUP BY,否则由于没有组,因此没有结果… 除非您添加GROUP BY,然后没有任何行,否则MAX / SUM等将返回NULL。只有COUNT传回没有结果的数字 编辑,有点晚:SUM会像MAX一样返回NULL 编辑,

  • 问题内容: 显然,该方法的返回类型为void,因此,它不返回任何内容。从这个意义上讲,我使用“返回”一词来表示将响应发送回请求它的客户端。 我正在尝试实现一个长轮询的Servlet。最好在我有想要发回的东西之前不发送响应,这将是有益的。因此,在doGet方法中,将连接的用户的ID和AsyncContext添加到映射中: 然后,当我有东西要发回时,我可以检索适当的上下文并写入其响应输出流: 但是,客

  • 问题内容: 有人可以提供goroutine返回的澄清值。从goroutine返回的值是否已存入抵押。 例如: 我们是否应该避免在go例程中避免返回值? 问题答案: 快速查看一下组装输出显示 该函数确实将其结果存储到堆栈中 因此,当从goroutine调用它时,它会将结果存储到堆栈中。但是,这是一个新的堆栈,当goroutine结束时,该堆栈会被破坏,因此无法获取返回值。 但是,无法检索这些结果。

  • 我想以毫秒为单位获取当前的UTC时间。我搜索了一下google,得到了System.currentTimeMillis()确实返回UTC时间的一些答案。但事实并非如此。如果我做了以下事情: 所有三个时间几乎相同(由于通话时间不同,时间相差毫秒)。 这个时间不是UTC时间,而是我的时区时间。如何在android中获取当前UTC时间?