我需要管理许多后台线程,这些后台线程使用某些对象作为键,但只有一个线程可以同时使用同一个对象,例如,当thread A
处理object A
时,如果要求thread B
使用的object A
,thread 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之类的行为。
答案 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具有值,则可以查看该值确定调度行为的年龄,例如返回旧值,返回旧值并安排幕后更新值或抛弃旧值太旧了,取得了一个干净的价值。