【问题标题】:Implement a cancelable thread manager for a unique object为唯一对象实现可取消的线程管理器
【发布时间】:2016-06-16 21:18:58
【问题描述】:

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

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

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 的行为。

【问题讨论】:

  • 为此使用 RxJava

标签: java android multithreading executorservice futuretask


【解决方案1】:

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

【讨论】:

  • 嘿,谢谢回复,如果我弄错了不是返回值只是显示了操作结果,虽然当我登录时,结果是真的但是线程一直在运行,我要问的是如何以及在哪里我可以停止可运行对象吗?
  • 你不能在 Java 中杀死一个正在运行的线程(你可以,但这是一个非常糟糕的做法)。正确的方法是为您的实例设置一个 volatile 布尔变量以要求它终止其处理。 ThreadPools 用于短期运行的线程。
  • @GuillaumeF。我明白你的建议,在循环中检查条件,但在第一次重复时,runnable 中的整个代码将执行如果你明白我的意思
  • 好吧,如果 FutureTask 尚未启动,您可以取消它。如果你不能取消它,那就意味着为时已晚。它已经在运行了。
  • 当然,我正在努力解决的问题是这样一个事实,即 run 方法将在运行之前被取消。它被认为是一行代码!虽然里面包含了很多代码行,但是我需要在中间取消这个方法。
【解决方案2】:

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

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

您应该更具体地说明您真正想要解决的问题。这个问题可能有更好的解决方案。

【讨论】:

    【解决方案3】:

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

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

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

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

    【讨论】:

      【解决方案4】:

      这里有两个主要问题 1) run 方法需要声明为同步的(在检查事物状态时避免竞争条件)和 2)future.cancel 不能暂停已经开始的工作。因此,将您自己的守卫/取消机制添加到可运行文件中。

      也就是说,最干净的解决方案是首先避免取消的需要,但是这个问题中没有足够的域详细信息来验证这是否可行。此类问题的常见模式是从 run 返回一个 Promise 并缓存该 Promise。 Promise 是异步操作结果的线程安全容器对象。如果相同的工作被安排两次,则可能会返回相同的承诺。如果一个promise有一个值,那么就可以查看该值有多旧来确定调度行为,例如返回旧值,返回旧值并在幕后安排更新值或丢弃旧值太旧并获取一个干净的值。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-04-02
        相关资源
        最近更新 更多