Java 未真正取消ExecutorService的未来任务

Java 未真正取消ExecutorService的未来任务,java,concurrency,executorservice,future,Java,Concurrency,Executorservice,Future,我将我的未来从Executor服务推送到哈希映射中。稍后,我可以在散列映射中调用Futures上的cancel。尽管结果是真的,但我后来在可调用过程中遇到了断点,就好像Future cancel()没有效果一样。我认为这里可能有两个不同的引用(即使在中断时引用ID是相同的),但我想知道是否有专家可以插话。下面是代码的样子: ExecutorService taskExecutor = Executors.newCachedThreadPool(); Map <String, Future&

我将我的未来从Executor服务推送到哈希映射中。稍后,我可以在散列映射中调用Futures上的cancel。尽管结果是真的,但我后来在可调用过程中遇到了断点,就好像Future cancel()没有效果一样。我认为这里可能有两个不同的引用(即使在中断时引用ID是相同的),但我想知道是否有专家可以插话。下面是代码的样子:

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()
,那么您需要自己分叉线程,而不是使用池。