使用Executors和callable从调用中转储调用堆栈时,我看到了奇怪的结果。来自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;
}
}
'主'线程:
main@1, prio=5, in group 'main', status: 'WAIT'
at sun.misc.Unsafe.park(Unsafe.java:-1)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:834)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedInterruptibly(AbstractQueuedSynchronizer.java:994)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(AbstractQueuedSynchronizer.java:1303)
at java.util.concurrent.FutureTask$Sync.innerGet(FutureTask.java:248)
at java.util.concurrent.FutureTask.get(FutureTask.java:111)
at com.test.tracked.AsynchronousCall.callFuture(AsynchronousCall.java:26)
at com.test.Main.main(Main.java:21)
调用callable的代码:
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();
}
}
答案 0 :(得分:4)
编译器添加了一个合成桥接方法来支持泛型。所以
@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";
}
(请注意,这在源代码中是不可能的,因为两种方法都具有相同的签名。)
在其他问题和答案中进一步解释了这一点:
答案 1 :(得分:2)
这是编译器添加的桥接方法的结果。
在JVM中,方法没有协变返回类型。尝试致电Object call()
将不致电String call()
- 如果没有Object call()
方法,则会抛出NoSuchMethodError
。因此,编译器添加类似于:
public Object call() throws Exception {
return call(); // the call() method that returns String, not this one
}
为什么会有Object call()
方法呢?由于泛型类型擦除 - 字节码不使用泛型类型。在字节码中,Callable
看起来像这样:
interface Callable {
Object call() throws Exception;
}
和ACallable
看起来像这样:(这不是有效的Java源代码,因为它包含两个具有相同名称和参数的方法)
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
}
}
您可以通过在生成的类文件上运行javap
来查看此内容。