小编典典

将代码从使用计时器移植到Scheduledexecutorservice

java

我正在尝试将代码从使用Java
计时器移植到使用Scheduledexecutorservice

我有以下用例

class A {

    public boolean execute() {
         try {
              Timer t = new Timer();
              t.schedule (new ATimerTask(), period, delay);
         } catch (Exception e) {
              return false;
         }
    }

}


class B {

    public boolean execute() {
         try {
              Timer t = new Timer();
              t.schedule (new BTimerTask(), period, delay);
         } catch (Exception e) {
              return false;
         }
    }

}

我应该用ScheduledExecutorService替换A类和B类中的Timer实例,并使ATimerTask和BTimerTask类成为Runnable类,例如

class B {

    public boolean execute() {
         try {
              final ScheduledExecutorService scheduler = 
   Executors.newScheduledThreadPool(1);

              scheduler.scheduleWithFixedDelay (new BRunnnableTask(), period, delay);
         } catch (Exception e) {
              return false;
         }
    }

}

这样对吗。

编辑:移植的主要动机之一是因为在TimerTask中引发的运行时异常会杀死一个线程,因此无法对其进行进一步调度。我想避免这种情况,以便即使我有运行时异常,该线程也应继续执行而不停止。


阅读 215

收藏
2020-11-23

共1个答案

小编典典

注意:您执行此操作的方式将泄漏线程!

如果您的课程B将保留下来,并且 每个实例 最终 将被关闭或关闭或释放,那么我将这样做:

class B {
  final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);

  public boolean execute() {
    try {
      scheduler.scheduleWithFixedDelay(new BRunnnableTask(), period, delay);
      return true;
    } catch (Exception e) {
      return false;
    }
  }

  public void close() {
    scheduler.shutdownNow();
  }
}

如果您不会在每个实例上进行这种清理,那么我会这样做:

class B {
  static final ScheduledExecutorService SCHEDULER = Executors.newCachedThreadPool();

  public boolean execute() {
    try {
      SCHEDULER.scheduleWithFixedDelay(new BRunnnableTask(), period, delay);
      return true;
    } catch (Exception e) {
      return false;
    }
  }
}

ExecutorService您在代码中分配的每个分配都会分配一个Thread。如果您制作了很多类实例,B则每个实例都会分配一个Thread。如果这些不能迅速收集到垃圾,那么您可能最终会分配成千上万个线程(但未使用,只是分配了),并且可能使整个服务器崩溃,使机器上的每个进程都挨饿,而不仅仅是您自己的JVM。我已经看到它在Windows上发生,并且我希望它也可以在其他OS上发生。

当您不打算在单个对象实例上使用生命周期方法时,静态缓存线程池通常是一种安全的解决方案,因为您只会保留实际 运行的
线程数,而不会为创建的每个实例分配一个线程尚未收集垃圾。

2020-11-23