【问题标题】:cancelling current task and reuse the same thread while creating another task in java在java中创建另一个任务时取消当前任务并重用同一个线程
【发布时间】:2017-07-10 19:08:47
【问题描述】:

请花时间阅读以下内容。非常感谢您的帮助

我有一个需要监控一些实时活动的场景。例如,一个方法在几毫秒内被实时调用。我必须像第一次调用该方法和最后一次调用该方法一样进行监视。

所以,在最后一次点击该方法之后,我需要等待某个时间,比如说 10 秒,看看它是否在这段时间内没有再次调用。如果它没有被调用,那么我需要运行一些代码。

我想使用 ExecuterService 并使用 newCachedThreadPool()。但我对如何实现这一点感到困惑。

如果你不确定我在说什么,举个例子,比如当网络出现故障并且你在哪里接收到心跳并且你突然停止接收它,然后你会在屏幕上显示一些错误消息,例如连接不可用。在我的情况下,它是一些第三方应用程序,它正在发送一些消息并且它只是一种通信方式。就像,我的应用程序发送了一些请求,而其他应用程序继续发送响应。因此,我需要监视该响应,并且需要知道我何时收到最后一个响应。

我的方法 - 我想在每次调用该方法时执行一个任务,该任务将等待 10 秒并在 10 秒内,如果再次调用该方法,它将以某种方式取消当前任务并将创建另一个任务(或如果可能的话重用),该任务将再次运行 10 秒。这将继续发生,直到收到最后一条消息(最后一次调用该方法时),然后在 10 秒延迟结束后,将执行任务并运行一些代码以在 UI 上显示错误消息。

我之前使用过 Timer,它解决了这个问题,但是作为 new Timer 产生了性能问题,每次收到新消息时都会实例化一个新的 TimerTask,因此会创建大量垃圾收集器无法快速回收的对象,从而导致 outOfMemory 错误并使服务器无响应。显然这是一个糟糕的代码,这就是我在这里寻求帮助的原因。

请帮助我提供一些解决此问题的方法。

【问题讨论】:

  • 我一直认为 ThreadPools 提供了易于使用的控制。如果我这样做,我不会使用它们,但这是我个人的喜好
  • 如果某些应用程序代码在 t 秒内没有执行,是否要发出警报?这是问题陈述吗?如果是,请重新表述您的问题以明确说明。如果不是,请重新表述您的问题以说明真正的问题。

标签: java multithreading performance threadpoolexecutor java-threads


【解决方案1】:

如果您使用最基本的工具来解决这个问题,这很容易——有时对于简单的问题,线程池等增强工具只会分散琐碎解决方案的注意力。

假设您有一个简单的线程 (Runnable)。该线程检查时间戳以查看该时间戳是否存在 10 秒。如果是你通知你的听众,如果不是你延迟几毫秒并再次检查。

现在您的方法所要做的就是在每次运行时将(易失性)时间戳更新为“现在”。这里可能还有一些其他的业务规则需要实现,但它应该是一个很好的基础。

现在唯一的问题是你如何通知你的听众。如果这种情况很少发生,您可能可以在您检查时间的同一个线程上调用它们——但我认为您排除了这一点。如果它发生得更频繁,但您不希望/不需要它来“嵌套”您的通知,您可以让第二个线程闲逛,除了在您的观察者线程触发时通知客户端之外没有其他目的。

如果您需要“嵌套”通知(在原始通知返回之前通知侦听器),那么您需要一个线程池来让您的通知发出。

最后我想如果你想捕捉每次你的计时器没有被调用 10 秒但你不想嵌套,你的计时线程可以将“事件”推送到线程安全队列中,而你的“通知”线程可以将它们拉下来并一次发送一个事件。

这应该涵盖所有可能性。

【讨论】:

  • 我也是这么想的。但是因为我只有我的手机并且今天得到了我的 300 代表,我很高兴你决定写下这个答案。一个提示:如果线程读取/写入时间戳在同一监视器上同步,则不需要 volatile。但我不确定哪个选项可以提供更好的“实时性能”。
  • @GhostCat 真的,谢谢。您可能还可以使用 AtomicLong——我猜这实际上是性能和易用性最好的。
【解决方案2】:

【讨论】:

    【解决方案3】:

    java.util.concurrent.Executors.newCachedThreadPool

    创建一个线程池,根据需要创建新线程,但会 当它们可用时重用以前构造的线程。这些 池通常会提高执行程序的性能 许多短暂的异步任务。调用执行将重用 以前构造的线程(如果可用)。如果没有现有线程 可用时,将创建一个新线程并将其添加到池中。线程 六十秒内未使用的将被终止并删除 从缓存中。因此,一个闲置时间足够长的池将 不消耗任何资源。请注意,具有相似属性但 可以创建不同的细节(例如,超时参数) 使用 ThreadPoolExecutor 构造函数

    由于您有许多短期任务,缓存线程池是最佳选择。

    简短示例:

    public class WorkerThread implements Runnable {
    
        private String command;
    
        public WorkerThread(String s){
            this.command=s;
        }
    
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName()+" Start. Command = "+command);
            processCommand();
            System.out.println(Thread.currentThread().getName()+" End.");
        }
    
        private void processCommand() {
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
        @Override
        public String toString(){
            return this.command;
        }
    }
    

    要运行WorkerThread,请使用:

    ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newCachedThreadPool();
    
    Runnable worker = new WorkerThread("threadName");
                executor.execute(worker);
    

    要停止WorkerThread,请使用:

    executor.shutdown();
    

    【讨论】:

    • 这对 OP 甚至没有任何帮助。他想要的是他的应用代码和监控代码之间的某种信号,而不是如何实现Runnable,谷歌已经有几百万个例子。
    • 他说:I want to use ExecuterService and use newCachedThreadPool(). But I am confused on how to implement this.
    • 他认为他需要ExecuterService,但如果您阅读他剩下的相当长且有些令人困惑的问题,您就会明白我在上面所说的内容。
    • 顺便说一句,我没有对你投反对票,但我看到其他人投了反对票。
    • 我们如何监控java中的方法调用?
    猜你喜欢
    • 1970-01-01
    • 2022-07-11
    • 2015-05-31
    • 1970-01-01
    • 2018-05-28
    • 2021-04-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多