Java 未真正取消ExecutorService的未来任务
我将我的未来从Executor服务推送到哈希映射中。稍后,我可以在散列映射中调用Futures上的cancel。尽管结果是真的,但我后来在可调用过程中遇到了断点,就好像Future cancel()没有效果一样。我认为这里可能有两个不同的引用(即使在中断时引用ID是相同的),但我想知道是否有专家可以插话。下面是代码的样子:Java 未真正取消ExecutorService的未来任务,java,concurrency,executorservice,future,Java,Concurrency,Executorservice,Future,我将我的未来从Executor服务推送到哈希映射中。稍后,我可以在散列映射中调用Futures上的cancel。尽管结果是真的,但我后来在可调用过程中遇到了断点,就好像Future cancel()没有效果一样。我认为这里可能有两个不同的引用(即使在中断时引用ID是相同的),但我想知道是否有专家可以插话。下面是代码的样子: ExecutorService taskExecutor = Executors.newCachedThreadPool(); Map <String, Future&
ExecutorService taskExecutor = Executors.newCachedThreadPool();
Map <String, Future<Object>> results = new HashMap <String, Future<Object>>();
Future<Object> future = taskExecutor.submit(new MyProcessor(uid));
results.put(uid, future);
ExecutorService taskExecutor=Executors.newCachedThreadPool();
Map results=newhashmap();
Future-Future=taskExecutor.submit(新的MyProcessor(uid));
结果:put(uid,未来);
我允许处理继续(这是一个在任务传入时提交任务的循环),稍后我可以通过调用以下方法尝试从外部源取消:
public static synchronized boolean cancelThread(String uid) {
Future<Object> future = results.get(uid);
boolean success = false;
if (future != null) {
success = (future.isDone() ? true : future.cancel(true));
if (success)
results.remove(uid);
}
return success;
}
公共静态同步布尔取消线程(字符串uid){
Future=results.get(uid);
布尔成功=假;
如果(未来!=null){
success=(future.isDone()?true:future.cancel(true));
如果(成功)
结果:移除(uid);
}
回归成功;
}
但我仍然在MyProcessor.call()中遇到一个“未取消”路径,在调用future.cancel()之后,即它实际上没有被取消
这件事我哪里做错了?这样做有更好的方法吗
我后来在可调用过程中遇到了断点,就好像Future cancel()没有效果一样
Future.cancel(true)
删除队列中尚未运行的作业,但如果该作业已在运行,则该作业将在运行该作业的线程上执行与Thread.interrupt()等效的操作。这将设置线程上的中断位,并导致任何sleep()
、wait()
,以及一些其他方法引发InterruptedException
重要的是要认识到它不会停止线程。您需要主动检查线程循环中的中断标志,或正确处理InterruptedException
有关更多详细信息,请参见此处我的SO答案:未来任务::布尔取消(布尔可能中断fRunning)
将在当前运行的线程上执行中断
FutureTask.java
public boolean cancel(boolean mayInterruptIfRunning) {
if (!(state == NEW &&
UNSAFE.compareAndSwapInt(this, stateOffset, NEW,
mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
return false;
try { // in case call to interrupt throws exception
if (mayInterruptIfRunning) {
try {
Thread t = runner;
if (t != null)
t.interrupt(); ////////////HERE/////////////
} finally { // final state
UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED);
}
}
} finally {
finishCompletion();
}
return true;
}
为中断
公共无效中断()
中断此线程。除非当前
线程正在中断自身,这是始终允许的
已调用此线程的checkAccess方法,这可能会导致
要抛出的SecurityException
如果该线程在wait()的调用中被阻塞,wait(long),
或对象类或join()的wait(long,int)方法,
join(long)、join(long,int)、sleep(long)或sleep(long,int)方法
则其中断状态将被清除,并且
接收中断异常
如果此线程在I/O操作中因可中断事件而被阻塞
然后通道将关闭,线程的中断状态
将被设置,并且线程将接收ClosedByInterruptException
如果该线程在选择器中被阻塞,则该线程的中断
将设置状态,并立即从选择返回
操作,可能使用非零值,就像选择器
已调用唤醒方法
如果前面的条件都不成立,那么这个线程的中断
将设置状态
中断一个非活动线程不需要有任何效果
抛出:SecurityException-如果当前线程无法修改此
线
总结;取消FutureTask
只有在线程被阻塞(在wait()调用中,…)时才有效,否则开发者有责任检查thread.currentThread().isInterrupted()
退出;在执行非阻塞操作时。也与:我明白了,这是有意义的-在可调用状态中,此时我没有处于等待()状态,因此它不会为我抛出InterruptedException。不幸的是,我试图取消的是在数据库启动后对其进行的单个语句调用,因此我最多可以测试线程是否在之后中断。为了澄清,这是请求取消时我可能使用的语句,即数据库中的PreparedStatement:'stmt.execute();'所以我想我必须让数据库完成这个过程,然后检查是否有中断。好的,我将它改为可运行线程而不是可调用线程,这样我就可以重写interrupt()方法,并在其中使用stmt.cancel()取消我的数据库语句;然而,它似乎是未来的。cancel(true)可能没有显式地调用这个中断方法,因为我从来没有进入过它。我想我在那里有些东西。问题是@Ryan是你正在向线程池提交一个Runnable
。它有自己的线程,因此它只使用thread.run()
方法。如果您需要覆盖interrupt()
,那么您需要自己分叉线程,而不是使用池。