当前位置: 首页 > 知识库问答 >
问题:

将任务移动到单独的线程,避免任务运行时重复

何修能
2023-03-14

我们在遗留代码和当前代码之间有一个粘合组件。本质上,整个遗留应用程序是单线程的,并且存在可怕的问题,单个指令的用户界面刷新可能会发生5到8次。

我想在第一次更新请求发生2秒后发布一条异步消息。

让我们不要纠结于为什么,这不是我真正想要做的,但我必须了解如何至少做到这一点,这样我才能实施真正的解决方案。

Runnable task = () -> {
    try {
        TimeUnit.SECONDS.sleep(2);
        messageBus.publishAsynch(new LegacyUiUpdateEvent());
    } catch (InterruptedException e) {
        // TODO Log something
        Thread.currentThread().interrupt();
    }
};

@Override
public void update(Observable arg0, Object arg1) {
    ExecutorService executor = Executors.newSingleThreadExecutor();
    if (futureTask == null || futureTask.isDone()) {
        futureTask = executor.submit(task);
        try {
            executor.awaitTermination(10, TimeUnit.SECONDS);
            executor.shutdownNow();
        } catch (InterruptedException e) {
            // TODO Log something
            Thread.currentThread().interrupt();
        }
    }
}

理论是:如果未来的任务不存在,我们会创建它,一旦它存在,如果它没有完成(因为这是错误的遗留更新4/x,其中x∈ [5,12]睡眠仍然有效)然后我们完全跳过,不创建新的执行器。

问题是,据我所知,执行者。提交(任务)实际上并不会在新的进程中发生。就像我说的,旧版应用程序是单线程的,在我将睡眠时间增加到15秒后,很明显它正在将当前的整个线程发送到睡眠状态。

我如何将我的任务放在一个全新的线程上(使用并发库)并避免多次执行该任务,即使update方法被调用的次数太多(这完全超出了我的控制)。我认为是未来。isDone()这玩意儿行得通,但不是100%

共有2个答案

任云瀚
2023-03-14

执行者。submit()会在新线程中启动任务,但就在执行器之后。等待终止(10,时间单位秒) 正在当前线程中等待任务完成。不需要在当前线程中等待,但需要有一种方法来确定任务是否已经在运行。

混乱的部分是每次都创建ExecutorService——没有必要每次都重新创建它。它可以是类的实例变量,可以重复使用。理想情况下,它将通过构造函数注入,以便创建它的类可以在确实需要时关闭它。

 private final ExecutorService executor = Executors.newSingleThreadExecutor();  // or injected through constructor
 private Future<?> futureTask;

@Override
public void update(Observable arg0, Object arg1) {
    if (futureTask == null || futureTask.isDone()) {
        futureTask = executor.submit(task);
    }
}
阎承嗣
2023-03-14

如果你是在Java8或更高这是一个更好的事情要做

CompletableFuture.runAsync(task);

因为这将在Fork-join线程池上执行,该线程池由JVM管理,您不会因为创建或关闭它而担心自己。当然,这将异步运行,符合您的需求。

 类似资料:
  • 问题内容: 我已经研究了很多关于Java线程的教程,但是找不到答案。 我的问题是:如何同时运行两个独立的线程? 我的情况是:我有两个任务; 保存一些数据到数据库 在移动设备上发送推送通知。 由于这两个任务是独立的,因此我想同时执行它们。 我尝试使用具有两个线程的线程池,但是问题是数据库任务很快完成,但是发送推送通知需要一些时间。 因此,当一个任务完成而另一个任务仍未完成时,它将引发异常。 我的代码

  • 我是JavaFx/并发的新手,所以我在JavaFX中阅读了并发教程,但是我仍然对JavaFX Gui中后台线程的实现有点困惑。 我试图编写一个与一些串行设备(使用JSSC-2.8)接口的小图形用户界面,并根据这些设备的响应更新图形用户界面。但是,在写入消息和设备响应之间有一个延迟,在任意的时间内使用Thread.sleep()对我来说不是一个可靠的编程方式。因此,我想使用并发包中的等待()和通知(

  • 问题内容: 我使用celery更新新闻聚合站点中的RSS feed。我为每个提要使用一个@task,看起来一切正常。 有一个细节我不确定如何处理:所有提要每分钟都使用@periodic_task更新一次,但是如果提要仍在启动新任务时从上一个定期任务更新,该怎么办?(例如,如果Feed确实很慢或离线,并且任务在重试循环中进行) 目前,我存储任务结果并按以下方式检查其状态: 也许我错过了一些使用芹菜机

  • 我正在使用 Kubernetes 作为容器编排器构建一个微服务应用程序。该应用程序现已启动并运行,但我有其他问题。那是在我的服务中,我每天都有一个计划任务运行,当服务部署时,将运行多个服务实例(通过设置副本编号),创建多个同时运行的任务。我期望的是只有一个服务任务实例将运行,而不是多个实例。有什么技术可以处理这种情况吗? 库伯内特斯 Asp.net核心构建微服务 CI/CD的基岩实现 Fabrik

  • 我回顾了这个问题的答案,其中提出了一些后续问题,涉及将解决方案泛化以支持每个类别的可变行数,现在我已经准备好了代码,可以将各种任务拆分为所需的行。 我已经使用了原来的小提琴并对其进行了修改,看到这里可以更好地理解这个概念。 我可以看到我们有一个必须一起工作的数字。我们首先似乎需要为每个将有多行的类别中断,我们需要将“y”属性设置为类别偏移量的十进制部分,并且我们需要在类别系列上应用翻译。 目前尚不

  • 我正在探索使用Spring Boot的异步servlet。据我所知,异步servlet用于在一个线程中执行长时间运行的任务,而不是容器为处理请求而启动的线程,这样容器就可以使用自己的线程来处理其他连接。基于这样的理解,我尝试了以下代码: 但问题是,运行的同一线程正在调用方法。不是应该不一样吗?