Java 如何让FutureTask在TimeoutException之后返回?
在下面的代码中,我在100秒后捕捉到一个TimeoutException。此时,我希望代码从main退出,程序终止,但它会一直打印到控制台。如何使任务在超时后停止执行Java 如何让FutureTask在TimeoutException之后返回?,java,futuretask,Java,Futuretask,在下面的代码中,我在100秒后捕捉到一个TimeoutException。此时,我希望代码从main退出,程序终止,但它会一直打印到控制台。如何使任务在超时后停止执行 private static final ExecutorService THREAD_POOL = Executors.newCachedThreadPool(); private static <T> T timedCall(Callable<T> c, long timeout, TimeUnit
private static final ExecutorService THREAD_POOL = Executors.newCachedThreadPool();
private static <T> T timedCall(Callable<T> c, long timeout, TimeUnit timeUnit) throws InterruptedException, ExecutionException, TimeoutException {
FutureTask<T> task = new FutureTask<T>(c);
THREAD_POOL.execute(task);
return task.get(timeout, timeUnit);
}
public static void main(String[] args) {
try {
int returnCode = timedCall(new Callable<Integer>() {
public Integer call() throws Exception {
for (int i=0; i < 1000000; i++) {
System.out.println(new java.util.Date());
Thread.sleep(1000);
}
return 0;
}
}, 100, TimeUnit.SECONDS);
} catch (Exception e) {
e.printStackTrace();
return;
}
}
private static final ExecutorService THREAD_POOL=Executors.newCachedThreadPool();
私有静态T timedCall(可调用c、长超时、TimeUnit TimeUnit)抛出InterruptedException、ExecutionException、TimeoutException{
未来任务=新的未来任务(c);
线程池执行(任务);
返回任务.get(超时,时间单位);
}
公共静态void main(字符串[]args){
试一试{
int returnCode=timedCall(新的可调用(){
公共整数调用()引发异常{
对于(int i=0;i<1000000;i++){
System.out.println(新的java.util.Date());
睡眠(1000);
}
返回0;
}
},100,时间单位为秒);
}捕获(例外e){
e、 printStackTrace();
返回;
}
}
一旦捕获到TimeoutException,您需要调用任务的cancel(true)方法
或者通过调用shutdownNow()关闭ExecutorService
或通过调用System.exit(0)退出VM
根据您的需要您需要在超时时取消任务(并中断其线程)。这就是
cancel(true)
方法的作用:
private static final ExecutorService THREAD_POOL = Executors.newCachedThreadPool();
private static <T> T timedCall(FutureTask<T> task, long timeout, TimeUnit timeUnit) throws InterruptedException, ExecutionException, TimeoutException {
THREAD_POOL.execute(task);
return task.get(timeout, timeUnit);
}
public static void main(String[] args) {
try {
FutureTask<Integer> task = new FutureTask<Integer>(new Callable<Integer>() {
public Integer call() throws Exception {
for (int i=0; i < 1000000; i++) {
if (Thread.interrupted()) return 1;
System.out.println(new java.util.Date());
Thread.sleep(1000);
}
return 0;
}
});
int returnCode = timedCall(task, 100, TimeUnit.SECONDS);
} catch (Exception e) {
e.printStackTrace();
task.cancel(true);
}
return;
}
private static final ExecutorService THREAD_POOL=Executors.newCachedThreadPool();
私有静态T timedCall(FutureTask任务、长超时、TimeUnit TimeUnit)抛出InterruptedException、ExecutionException、TimeoutException{
线程池执行(任务);
返回任务.get(超时,时间单位);
}
公共静态void main(字符串[]args){
试一试{
FutureTask task=新的FutureTask(新的可调用(){
公共整数调用()引发异常{
对于(int i=0;i<1000000;i++){
if(Thread.interrupted())返回1;
System.out.println(新的java.util.Date());
睡眠(1000);
}
返回0;
}
});
int returnCode=timedCall(任务,100,时间单位为秒);
}捕获(例外e){
e、 printStackTrace();
任务。取消(true);
}
返回;
}
您的呼叫必须能够在需要时快速停止
您的代码:
public Integer call() throws Exception {
for (int i=0; i < 1000000 && !task.cancelled(); i++) {
System.out.println(new java.util.Date());
Thread.sleep(1000); // throws InterruptedException when thread is interrupted
}
return 0;
}
public Integer call()引发异常{
对于(int i=0;i<1000000&&!task.cancelled();i++){
System.out.println(新的java.util.Date());
Thread.sleep(1000);//当线程被中断时抛出InterruptedException
}
返回0;
}
由于调用了Thread.sleep()
,已经能够做到这一点。关键是futureTask.cancel(true)
将中断其他线程,您的代码需要对此中断做出反应Thread.sleep()。如果您没有使用Thread.sleep()
或其他可中断的阻塞代码,您必须自己检查Thread.currentThread().isInterrupted()
,并在发现这是真的时尽快退出(例如,通过抛出new InterruptedException()
)
您需要调用futureTask.cancel(true)代码>从异常处理程序取消并中断运行任务的线程
我的建议是学习中断机制(这是一篇很棒的文章:),并使用它。!task.cancelled()应该是!正如djna最初写的,我认为使用中断会更好。首先,您的可调用代码根本不需要知道task
。其次,当您在可调用代码中使用各种阻塞操作(如Thread.sleep()
)时,它们不会对task.isCancelled()作出反应,但通常会对中断作出反应。因此,使用cancel(true)
并让代码意识到中断通常是最好的方法。(你的代码也会更一般,因为中断机制在Java中被广泛使用)我想我的观点是“中断是一种合作机制。”()@Peter Nice article!我已相应地更改了答案。cleary代码未经测试<代码>任务
将在捕获
块中未定义