[英]AutoCloseable Delayed Execution in try-resource-block
I have noticed that the execution of the close method on AutoCloseable objects is sometimes delayed. 我注意到在AutoCloseable对象上执行close方法有时会延迟。 It's normally executed within a millisec or two, but sometimes it takes up to a hundred millisecs or more.
通常在一或两个毫秒内执行,但有时最多需要一百个毫秒或更多。
I am unable to find Java documentation describing the expected timing of try-with-resource. 我找不到描述try-with-resource的预期时间的Java文档。 Can someone help explain what why there is sometimes such a large delay?
有人可以帮忙解释一下为什么有时会有这么大的延迟吗?
Below is a test to show this. 下面是测试以证明这一点。 The results vary, but if ran enough, results begin to show delayed execution of the close method.
结果各不相同,但如果运行得足够,结果将开始显示close方法的执行延迟。
public class ClosableTest {
public class TimerResource implements AutoCloseable {
private Instant startTime;
private long sleepTime;
private long actualTime;
public TimerResource() {
startTime = Instant.now();
}
public void setSleepTime(long sleepTime) {
this.sleepTime = sleepTime;
}
public void setActualTime(long actualTime) {
this.actualTime = actualTime;
}
@Override
public void close() throws Exception {
long closeTime = Duration.between(startTime, Instant.now()).toMillis();
//System.out.println(String.format("%s: Sleep time: %d; Actual time: %d; Closed time: %s", Thread.currentThread().getName(), sleepTime, actualTime, closeTime));
if (closeTime > actualTime+5) {
System.out.println("Close took more than 5ms");
System.out.println(String.format("\t%s: Sleep time: %d; Actual time: %d; Closed time: %s", Thread.currentThread().getName(), sleepTime, actualTime, closeTime));
}
}
}
@Test
public void timingTest() {
Instant start;
long realDuration;
for (int i = 0; i < 100; i++) {
try (TimerResource timer = new TimerResource()) {
start = Instant.now();
long sleepTime = 10L + (long) (400 * Math.random());
timer.setSleepTime(sleepTime);
Thread.sleep(sleepTime);
realDuration = Duration.between(start, Instant.now()).toMillis();
timer.setActualTime(realDuration);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
The close() is called immediately. close()被立即调用。 However when you try to determine this empirically, you are only as reliable as your benchmark.
但是,当您尝试凭经验确定这一点时,您只能像基准一样可靠。
BTW If you call System.nanoTime()
in a tight loop, you can see jumps in time of 1 - 50 ms due to the process being rescheduled. 顺便说一句,如果在紧密循环中调用
System.nanoTime()
,由于重新安排了进程,您会看到1到50毫秒的时间跳跃。 You can see this on your machine by running this test tools https://github.com/OpenHFT/Java-Thread-Affinity/blob/master/affinity/src/main/java/net/openhft/affinity/MicroJitterSampler.java 您可以通过运行以下测试工具在您的计算机上看到此信息:https://github.com/OpenHFT/Java-Thread-Affinity/blob/master/affinity/src/main/java/net/openhft/affinity/MicroJitterSampler.java
If you look at the byte code for this example. 如果您查看此示例的字节码。
public static void main(String... args) {
try (PrintWriter pw = new PrintWriter(System.out)) {
pw.println("Hello World");
}
}
you can see that close is called immediately after println 您可以看到在println之后立即调用close
L11
LINENUMBER 13 L11
NEW java/io/PrintWriter
DUP
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
INVOKESPECIAL java/io/PrintWriter.<init> (Ljava/io/OutputStream;)V
ASTORE 1
L12
ACONST_NULL
ASTORE 2
L3
LINENUMBER 14 L3
ALOAD 1
LDC "Hello World"
INVOKEVIRTUAL java/io/PrintWriter.println (Ljava/lang/String;)V
L4
LINENUMBER 15 L4
ALOAD 1
IFNULL L13
ALOAD 2
IFNULL L14
L0
ALOAD 1
INVOKEVIRTUAL java/io/PrintWriter.close ()V
L1
GOTO L13
L2
For the sake of brevity I have removed the try/finally byte code which is not executed unless there is a Throwable. 为了简洁起见,我删除了try / final字节代码,除非存在Throwable,否则不会执行。
I don't believe there should be a significant
difference between both cases. 我不认为这两种情况之间应该有
significant
差异。 As per java docs . 根据java docs 。
Try with resource
translate like below. Try with resource
如下所示的Try with resource
翻译。
Suppose your try with resource looks like 假设您尝试使用的资源看起来像
try ({VariableModifier} R Identifier = Expression ...)
Block
Will translate to : 将转换为:
{
final {VariableModifierNoFinal} R Identifier = Expression;
Throwable #primaryExc = null;
try ResourceSpecification_tail
Block
catch (Throwable #t) {
#primaryExc = #t;
throw #t;
} finally {
if (Identifier != null) {
if (#primaryExc != null) {
try {
Identifier.close();
} catch (Throwable #suppressedExc) {
#primaryExc.addSuppressed(#suppressedExc);
}
} else {
Identifier.close();
}
}
}
}
So it is clear that try with resource and normal try-catch
are nearly same
. 因此很明显,使用资源进行尝试和正常
try-catch
nearly same
。 The only difference is that you may put / or not all the checks generated during translation of the try with resource
. 唯一的区别是,您可以/不使用
try with resource
翻译时生成的所有检查。
Can someone help explain what why there is sometimes such a large delay?
有人可以帮忙解释一下为什么有时会有这么大的延迟吗?
Sometimes large delay may be due to several reason like CPU usage at that time, available memory, GC etc. 有时,较大的延迟可能是由于多种原因造成的,例如当时的CPU使用率,可用内存,GC等。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.