Java 使用Callable时出现奇怪的调用堆栈

Java 使用Callable时出现奇怪的调用堆栈,java,java.util.concurrent,Java,Java.util.concurrent,当使用Executors和callable从调用中转储调用堆栈时,我看到了奇怪的结果。可调用的方法在调用堆栈中出现两次 pool-1-thread-1@454, prio=5, in group 'main', status: 'RUNNING' at com.test.tracked.ACallable.call(ACallable.java:15) at com.test.tracked.ACallable.call(ACallable.java:9) a

当使用Executors和callable从调用中转储调用堆栈时,我看到了奇怪的结果。可调用的方法在调用堆栈中出现两次

pool-1-thread-1@454, prio=5, in group 'main', status: 'RUNNING'
      at com.test.tracked.ACallable.call(ACallable.java:15)
      at com.test.tracked.ACallable.call(ACallable.java:9)
      at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334)
      at java.util.concurrent.FutureTask.run(FutureTask.java:166)
      at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
      at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
      at java.lang.Thread.run(Thread.java:722)
如您所见,方法ACallable在堆栈中出现两次:第9行是ACallable类的声明,第15行是方法签名:

package com.test.tracked;

import java.util.concurrent.Callable;

/**
 *  A callable test class.
 *  
 */
public final class ACallable
    implements Callable<String> {
  private final String who;

  @Override
  public String call() throws Exception {
    Thread.dumpStack();
    return "Hello "+who+" from callable";
  }

  public ACallable(String who) {
    this.who = who;
  }

}
调用可调用函数的代码:

package com.test.tracked;

import java.io.Closeable;
import java.io.IOException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeoutException;



/**
 * Aynchronous call
 */
public class AsynchronousCall implements Closeable {

  private final ExecutorService executorService;


  public AsynchronousCall() {
    executorService = Executors.newSingleThreadExecutor();
  }

  public String callFuture(String who) throws InterruptedException, ExecutionException, TimeoutException {
    Thread.dumpStack();
    String ret = executorService.submit(new ACallable(who)).get();
    System.out.println("callFuture from " + getClass().getName() + " return " + ret);
    return ret;
  }

  @Override
  public void close() throws IOException {
    executorService.shutdownNow();
  }
}

编译器添加了一个合成桥方法来支持泛型。所以

@Override
public String call() throws Exception {
    Thread.dumpStack();
    return "Hello "+who+" from callable";
}
在编译的
.class
文件中,实际上有两种方法

// actual method
public Object call() throws Exception {
    return call(); // the other call
} 

// your implementation
public String call() throws Exception {
    Thread.dumpStack();
    return "Hello "+who+" from callable";
}
(请注意,这在源代码中是不可能的,因为两个方法具有相同的签名。)

其他问题和答案对此作了进一步解释:


这是编译器添加的桥接方法的结果

在JVM中,方法没有协变的返回类型。尝试调用
对象调用()
不会调用
字符串调用()
-如果没有
对象调用()
方法,它将抛出
NoSuchMethodError
。因此编译器添加了一个桥接方法,类似于:

public Object call() throws Exception {
    return call(); // the call() method that returns String, not this one
}
为什么有一个
对象调用()
方法?由于泛型类型擦除,字节码不使用泛型类型。在字节码中,
Callable
如下所示:

interface Callable {
    Object call() throws Exception;
}
ACallable
看起来是这样的:(这不是有效的Java源代码,因为它包含两个具有相同名称和参数的方法)


您可以在生成的类文件上运行
javap

what determing return call();将调用返回字符串的call(),而不是调用返回对象的call():)@PrashantShilimkar语言确实如此。这就是它的实现方式。
interface Callable {
    Object call() throws Exception;
}
class ACallable implements Callable {
    private final String who;

    // does NOT override the method in Callable due to the different return type
    public String call() throws Exception {
        Thread.dumpStack();
        return "Hello "+who+" from callable";
    }

    // overrides the method in Callable
    public Object call() throws Exception {
        return call(); // the version of call() that returns String
    }
}