Java try资源块中可自动关闭的延迟执行
我注意到在自动关闭对象上执行close方法有时会延迟。它通常在一两毫秒内执行,但有时需要100毫秒或更长时间 我找不到描述使用资源进行尝试的预期时间的Java文档。有人能解释一下为什么有时会有如此大的延迟吗 下面是一个测试来证明这一点。结果各不相同,但如果运行的时间足够长,结果开始显示close方法的延迟执行Java try资源块中可自动关闭的延迟执行,java,performance,Java,Performance,我注意到在自动关闭对象上执行close方法有时会延迟。它通常在一两毫秒内执行,但有时需要100毫秒或更长时间 我找不到描述使用资源进行尝试的预期时间的Java文档。有人能解释一下为什么有时会有如此大的延迟吗 下面是一个测试来证明这一点。结果各不相同,但如果运行的时间足够长,结果开始显示close方法的延迟执行 public class ClosableTest { public class TimerResource implements AutoCloseable {
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();
}
}
}
}
公共类ClosableTest{
公共类TimerResource实现自动关闭{
私人即时启动时间;
私人长时间睡眠;
私人长实际时间;
公共时间资源(){
startTime=Instant.now();
}
公共空闲设置睡眠时间(长睡眠时间){
this.sleepTime=睡眠时间;
}
公共无效设置实际时间(长实际时间){
this.actualTime=实际时间;
}
@凌驾
public void close()引发异常{
long closeTime=Duration.between(startTime,Instant.now()).toMillis();
//System.out.println(String.format(“%s:睡眠时间:%d;实际时间:%d;关闭时间:%s”,Thread.currentThread().getName(),sleepTime,actualTime,closeTime));
如果(关闭时间>实际时间+5){
System.out.println(“关闭时间超过5毫秒”);
System.out.println(String.format(“\t%s:睡眠时间:%d;实际时间:%d;关闭时间:%s”,Thread.currentThread().getName(),sleepTime,actualTime,closeTime));
}
}
}
@试验
公共无效时间测试(){
即时启动;
持续时间长;
对于(int i=0;i<100;i++){
try(TimerResource timer=new TimerResource()){
start=Instant.now();
长睡眠时间=10L+(长)(400*Math.random());
定时器。设置睡眠时间(睡眠时间);
睡眠(睡眠时间);
realDuration=Duration.between(start,Instant.now()).toMillis();
timer.setActualTime(realDuration);
}捕获(例外e){
e、 printStackTrace();
}
}
}
}
我认为这两种情况之间不应该有显著的差异。根据java<代码>尝试使用资源如下翻译
假设您对资源的尝试如下所示
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 with resource和normaltry catch
几乎相同。唯一的区别是,您可能会放置/或不放置在翻译时生成的所有检查,请尝试使用资源
有人能解释一下为什么有时会有这么大的
耽搁
有时,较大的延迟可能是由于几个原因造成的,如当时的CPU使用情况、可用内存、GC等。我认为这两种情况之间不应该有显著的差异。根据java<代码>尝试使用资源
如下翻译
假设您对资源的尝试如下所示
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 with resource和normaltry catch
几乎相同。唯一的区别是,您可能会放置/或不放置在翻译时生成的所有检查,请尝试使用资源
有人能解释一下为什么有时会有这么大的
耽搁
有时,较大的延迟可能是由于几个原因造成的,如当时的CPU使用情况、可用内存、GC等。立即调用close()。然而,当你试图以经验来确定这一点时,你只会像你的基准一样可靠
顺便说一句,如果您在一个紧密循环中调用System.nanoTime()
,您可以看到由于进程被重新调度而导致的1-50毫秒的时间跳跃。通过运行此测试工具,您可以在计算机上看到这一点
如果你看一下这个例子的字节码
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
L11
线路号13 L11
新的java/io/PrintWriter
重复
GETSTATIC java/lang/System.out:Ljava/io/PrintStream;
调用特定的java/io/PrintWriter。(Ljava/io/OutputStream;)V
阿斯托尔1号
L12
空的
阿斯托尔2号
L3
行号14 L3
阿洛德1号
最不发达国家“你好,世界”
invokeVirtualJava/io/PrintWriter.println(Ljava/lang/String;)V
L4
线路号15 L4
阿洛德1号
IFNULL L13
阿洛德2号
IFNULL L14
L0
阿洛德1号
invokeVirtualJava/io/PrintWriter.close()V
L1
转到L13
L2
为简洁起见,我删除了try/finally字节码,除非有可丢弃的,否则不会执行该字节码。立即调用close()。然而,当你试图以经验来确定这一点时,你只会像你的基准一样可靠
顺便说一句,如果您在一个紧密循环中调用System.nanoTime()
,您可以看到由于进程被重新调度而导致的1-50毫秒的时间跳跃。通过运行此测试工具,您可以在计算机上看到这一点
如果你看一下这个例子的字节码
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
L11
线路号13 L11
新的java/io/PrintWriter
重复
GETSTATIC java/lang/System.out:Ljava/io/PrintStream;
调用特定的java/io/PrintWriter。(Ljava/io/OutputStream;)V
阿斯托尔1号
L12
空的
阿斯托尔2号
L3
行号14 L3
阿洛德1号
最不发达国家“你好,世界”
invokeVirtualJava/io/PrintWriter.println(Ljava/lang/String;)V
L4
线路号15 L4
阿洛德1号
IFNULL L13
阿洛德2号
IFNULL L14
L0
阿洛德1号
invokeVirtualJava/io/PrintWriter.close()V
L1
转到L13
L2
为简洁起见,我删除了try/finally字节码,除非有可丢弃的,否则不会执行该字节码。这可能会有很多字节码