为唯一对象实现可取消的线程管理器

时间:2016-06-16 21:18:59

标签: java android multithreading executorservice futuretask

我需要管理许多后台线程,这些后台线程使用某些对象作为键,但只有一个线程可以同时使用同一个对象,例如,当thread A处理object A时,如果要求thread B使用的object Athread A应该在thread B运行之前取消。

这是我的代码,但是当我运行时,第一个线程不会停止并继续第二个线程:

private static ExecutorService mExecutor = Executors.newCachedThreadPool();
private static ConcurrentMap<Object, Future> mRunningTasks = new ConcurrentHashMap<>();
public static void run(final Runnable runnable, final Object key) {
    Future<?> future = mRunningTasks.get(key);
    if (future != null) {
        future.cancel(true);
    }
    future = new FutureTask<>(new Runnable() {
        @Override
        public void run() {
            //How to handle InterruptedException here ?
            //while there's no potential to throw an InterruptedException
            runnable.run();
            mRunningTasks.remove(key);
        }
    }, null);
    mRunningTasks.put(key, future);
    mExecutor.execute((FutureTask) future);
}

我在这里缺少什么?

提前致谢。

PS: 当使用Picasso作为关键对象取消请求时,我需要ImageView API之类的行为。

4 个答案:

答案 0 :(得分:0)

Future.cancel()的文档说它试图取消任务,但可能不成功。您需要检查布尔返回值以查看它是否实际取消。

答案 1 :(得分:0)

您的代码中还有其他多种竞争条件。

ConcurrentHashMap是线程安全的,但你使用它的方式不是。 你可能会: *多次取消未来 *添加未来而不取消前一个 *从地图中删除错误的未来

您应该更具体地了解您实际想要解决的问题。可能有更好的解决方案来解决这个问题。

答案 2 :(得分:0)

你想要杀死线程(Thread.stop()),这是一种非常糟糕的做法,并且由于多种原因而被弃用......不仅因为它没有对线程负责,因为它是由ThreadPool,但杀死它会破坏算法原子性的概念,使您的软件处于可能未确定的状态。

如果尚未启动,您可以取消FutureTask。如果您无法取消它,则表示它已在运行。在现代多核处理器上,这种速度非常快。

ThreadPool通常用于短期运行的线程。但在您的情况下,正确结束任务的正确方法是在任务类中设置volatile boolean变量并定期检查它以离开该方法。

InterruptedException仅在您的Thread等待或正在休眠时抛出,这在您当前的演示代码中不存在。如果您的Thread实际上正在等待或正在休眠,请将.notify()发送到监视器对象以中断它,然后抓住Exception中的try {} catch()

答案 3 :(得分:0)

这里有两个主要问题:1)run方法需要声明为synchronized(在检查事物状态时避免竞争条件)和2)future.cancel不能停止已经开始的工作。因此,为runnables添加自己的防护/取消机制。

尽管如此,最干净的解决方案是首先避免需要取消,但是在这个问题中没有足够的域细节来验证这是否可行。这类问题的一个常见模式是从运行中返回一个promise并缓存promise。 promise是异步操作结果的线程安全容器对象。如果安排两次相同的工作,则可以返回相同的承诺。如果promise具有值,则可以查看该值确定调度行为的年龄,例如返回旧值,返回旧值并安排幕后更新值或抛弃旧值太旧了,取得了一个干净的价值。