java为唯一对象实现可取消的线程管理器
我需要管理许多后台线程,这些线程使用一些对象作为键,但只有一个线程可以同时使用同一个对象,例如,当thread A
正在处理object A
时,如果thread B
调用了object A
来处理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:
当使用ImageView
作为键对象取消请求时,我需要类似Picasso
API的行为
# 1 楼答案
未来的文件。cancel()表示它试图取消任务,但可能不成功。您需要检查布尔返回值以查看它是否实际取消
# 2 楼答案
代码中还有多个其他条件
ConcurrentHashMap是线程安全的,但您使用它的方式不是。 你可以: *多次取消未来 *添加未来而不取消上一个未来 *从地图中删除错误的未来
你应该更具体地说明你实际上想要解决的问题。也许有更好的办法来解决这个问题
# 3 楼答案
这里有两个主要问题1)run方法需要声明为synchronized(在检查事物状态时避免争用条件)和2)future。cancel无法停止已开始的工作。因此,在runnables中添加您自己的防护/取消机制
这就是说,最干净的解决方案是首先避免取消,但是在这个问题中没有足够的域细节来验证这是否可行。这类问题的一种常见模式是从运行中返回承诺并缓存承诺。承诺是异步操作结果的线程安全容器对象。如果同一工作安排两次,则可能会返回相同的承诺。如果一个承诺有一个值,则可以查看该值的使用年限来确定调度行为,例如返回旧值、返回旧值并在幕后计划更新该值,或者将旧值丢弃为太旧并获取干净的值
# 4 楼答案
您想杀死线程(
Thread.stop()
),这是一种非常糟糕的做法,由于许多原因被弃用。。。不仅因为线程由ThreadPool
管理,所以您对线程没有责任,而且杀死它会破坏算法原子性的概念,使软件处于可能不确定的状态如果
FutureTask
尚未启动,您可以取消它。如果无法取消,则表示它已在运行。这在现代多核处理器上发生得非常快ThreadPool
通常用于短期运行的线程。但是在您的情况下,正确结束任务的方法是在任务类中设置一个volatile boolean
变量,并定期检查它以离开该方法InterruptedException
仅在您的Thread
正在等待或睡眠时才会抛出,而当前演示代码中不存在这种情况。如果您的Thread
实际上正在等待或睡眠,则向监视器对象发送一个.notify()
来中断它,并捕获try {} catch()
中的Exception