可以'this'传递给ScheduledExecutorService.scheduleWithFixedDelay()吗?

时间:2012-12-18 15:22:33

标签: java multithreading concurrency scheduled-tasks polling

我正在考虑将java.util.concurrent包用于简单的轮询类。我们对可用于实现此目的的类,接口和方法的范围感到有点困惑,因此需要一些指导。以下是我的想法:

要做的第一个决定是如何实例化用于管理计划的类。有几种可能的选择,例如:

ScheduledThreadPoolExecutor scheduledThreadPoolExecutor =
    new ScheduledThreadPoolExecutor(corePoolSize)

...或...

ScheduledExecutorService scheduledExecutorService =
    Executors.newSingleThreadScheduledExecutor();

...或...

ScheduledExecutorService scheduledExecutorService =
    Executors.newScheduledThreadPool(corePoolSize);

我倾向于最后一个,但想知道一个明智的corePoolSize是什么 - 也许是为了让事情变得简单?

编辑: 最后,我发现使用top方法的最大好处(即直接实例化ScheduledThreadPoolExecutor)。 ThreadPoolExecutor提供getActiveCount()以获取活动线程数。这使我能够实施pause()方法,等待暂停实际生效 - 请参阅discussion

下一个决定是致电scheduleAtFixedRate还是scheduleWithFixedDelay。我倾向于scheduleWithFixedDelay(),因为轮询规律并不是那么重要,我不喜欢在瓶颈之后快速连续发生多次民意调查的想法。

但问题是:使用单个类来启动轮询并表示线程是否可行/可取? E.g:

public class Poller extends Thread {
    @Override
    public void run() {
        ...
    }

    public void startPolling() {
        ScheduledExecutorService exec = Executors.newScheduledThreadPool(1);
        exec.scheduleWithFixedDelay(this, 0, 5000, TimeUnit.MILLISECONDS);
    }
}

我不确定的主要部分是第一个scheduleWithFixedDelay()参数:是否会为每次执行实例化此类的新实例?否则它肯定不会工作,因为无法在同一个Thread实例上调用run()两次?

2 个答案:

答案 0 :(得分:4)

正如其他人所评论的那样,您需要更改的是Thread to Runnable。您可能希望添加一些安全防护,以便不会运行多个任务。

public class Poller implements Runnable {
    final ScheduledExecutorService exec = Executors.newSingleThreadScheduledExecutor();
    Future future = null;

    @Override
    public void run() {
        ...
    }

    public void startPolling() {
        if (future != null && !future.isDone()) {
           future.cancel(true); // stop before restarting
           // or
           return; // already running
        }
        future = exec.scheduleWithFixedDelay(this, 0, 5000, TimeUnit.MILLISECONDS);
    }
}

BTW:如果你有Java 5.0,run()方法没有@Override。对于Java 6+,您应该拥有@Override。

  

是否会为每次执行实例化此类的新实例?

使用new运算符时会创建一个新实例。

  

否则肯定无法运行run()肯定无法在同一个Thread实例上调用两次?

它可以工作,因为在您的代码中使用Thread会让您感到困惑,因为您创建的线程未被使用。它只需要Runnable

答案 1 :(得分:2)

单线程方法可以使用Poller实现,如下所示:

public class Poller implements Runnable {
    public void run() {
        while ( mayContinue ) {
            poll();
            Thread.sleep(5000);
        }
    }
}