我注意到在AutoCloseable对象上执行close方法有时会延迟。它通常在一两毫秒内执行,但有时需要一百毫秒或更多。
我无法找到描述try-with-resource预期时间的Java文档。有人可以帮助解释为什么有时会出现如此大的延迟吗?
以下是显示此问题的测试。结果有所不同,但如果运行得足够多,结果会开始显示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();
}
}
}
}
答案 0 :(得分:3)
立即调用close()。但是,当您尝试根据经验确定时,您只能像基准一样可靠。
BTW如果你在紧密循环中调用System.nanoTime()
,由于重新安排了进程,你可以看到1到50毫秒的跳跃。您可以通过运行此测试工具https://github.com/OpenHFT/Java-Thread-Affinity/blob/master/affinity/src/main/java/net/openhft/affinity/MicroJitterSampler.java
如果查看此示例的字节代码。
public static void main(String... args) {
try (PrintWriter pw = new PrintWriter(System.out)) {
pw.println("Hello World");
}
}
你可以看到在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
为了简洁起见,我删除了try / finally字节代码,除非有Throwable,否则不执行该代码。
答案 1 :(得分:1)
我不相信这两种情况之间应该有significant
的差异。根据java docs。 Try with resource
翻译如下。
假设您尝试使用资源看起来像
try ({VariableModifier} R Identifier = Expression ...)
Block
将翻译为:
{
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();
}
}
}
}
很明显,尝试使用资源和普通try-catch
是nearly same
。唯一的区别是您可以在翻译try with resource
期间生成/不执行所有检查。
有人可以帮助解释为什么有时这么大的原因 延迟?
有时大延迟可能是由于当时的CPU使用率,可用内存,GC等原因造成的。