java - 从Handler迁移到ScheduledExecutorService进行调度

标签 java android multithreading concurrency scheduler

我的目标是安排一项以非均匀速率发生的经常性工作。我将从第一个 fragment 迁移到第二个 fragment :

第一:

Handler mHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        if (msg.what == MSG1) {               
            //recurrent job here              
            long nextTime = nextTime();
            sendMessageAtTime(obtainMessage(MSG1), nextTime);
            }
        }
    }
};

第二:

ScheduledExecutorService mExecutor;
while (true){
        mExecutor.schedule(new Callable() {
                public Object call() throws Exception {
                    long startTime = SystemClock.uptimeMillis();                       
                    //recurrent job here 
                    delay = nextTime() - startTime ;
                    return true;
                }
            }, delay, TimeUnit.MILLISECONDS);
}

我的问题是:

1- 在第一个代码 fragment 中,mHandler 所引用的线程是否可以在作业之间自由执行其他任务或处理其他消息?

2-但是在第二个 fragment 中,线程始终忙于循环。对吗?

3-如何重写第二个代码,以便我不会丢失作业之间的线程 Activity (延迟)?

非常感谢任何帮助

最佳答案

您的第二个代码将无法按预期工作。第一个任务被调度并等待执行后,while 循环继续调度更多任务,所有任务都有相同的延迟。因此,您最终将面临数千甚至数百万个任务。当然,因为主线程正在运行无限循环而没有任何等待,所以它一直很忙。这可能不是您想要的。

您应该更好地使用比上面处理程序使用的类似方法:

final ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
executor.schedule(() -> {
    // do work
    // reschedule
    executor.schedule(this, nextTime() - System.currentTimeMillis());
}, delay, TimeUnit.MILLISECONDS);

(当然,您还应该检查重新安排时指定的延迟是否不是负数)。

更新:如果您需要单独处理每次执行的结果,则可能需要使用与第二个代码示例类似的另一种方法。它在循环内安排任务执行,并在结果可用时将结果移交给消费者。 (请注意循环内的 future.get() ,它会导致循环线程暂停,直到任务完成)。

public static <T> void schedule(ScheduledExecutorService scheduler,
            Schedule schedule, Callable<T> task, Consumer<? super T> consumer)
            throws InterruptedException, ExecutionException {
    while (true) {
        if (Thread.interrupted()) throw new InterruptedException();

        long delay = schedule.nextTime() - System.currentTimeMillis();
        if (delay < 0) continue; // skip this step

        ScheduledFuture<? extends T> future = scheduler.schedule(task,
                                              delay, schedule.getUnit());
        consumer.accept(future.get());
    }
}

还要注意中断检查,以便其他线程可以通过中断循环线程来停止执行。如果您也想在后台线程上运行该方法,这可以简化在另一个任务中使用此方法的过程。

Schedule 可以是一个提供对调度信息的访问的功能接口(interface):

@FunctionalInterface
public interface Schedule {
    long nextTime();
    default TimeUnit getUnit() { return TimeUnit.MILLISECONDS; }
}

顺便说一句:android.os.Handler 是在 android 中执行您想要的操作的一种非常好的方法。因此,如果您确实需要它的功能(例如获取 Future 结果),您应该只迁移到 ScheduledExecutorService

关于java - 从Handler迁移到ScheduledExecutorService进行调度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25212803/

相关文章:

java - 骑士的最短路径(BFS)

java - 使用 JSTL 如何确定 forEach 之前哪个变量为 null

java - 是否可以在 Windows Phone 上的 C# 中运行 java 程序?

android - 拖放从 SQLiteDatabase 填充的 RecyclerView

java - 多线程 "unpredictable"行为

Java 密码填充错误

java - 如何为多部分表单发布禁用 Java HttpURLConnection 中的缓冲?

android 禁用 3 个选项卡中的 2 个

android - 在不添加到 backstack 的情况下弹出 backstack 时找不到 id 的 View

c# - 关于逻辑/算法的想法以及如何防止线程写入 Sql Server 中的竞争