Thread.sleep()VS Executor.scheduleWithFixedDelay()

时间:2012-11-16 18:11:05

标签: java multithreading thread-sleep scheduledexecutorservice

目标:每隔一段时间执行一些代码。

问题:就性能而言,是否存在显着差异:

while(true) {
    execute();
    Thread.sleep(10 * 1000);
}

executor.scheduleWithFixedDelay(runnableWithoutSleep, 0, 10, TimeUnit.SECONDS);

当然,后一种选择更犹豫不决。然而,我想知道我是否应该开始一项名为“花几天时间重构遗留代码以告别Thread.sleep()”的冒险。

更新: 此代码在超级/超级/超高负载环境中运行。

4 个答案:

答案 0 :(得分:10)

你正在处理几十秒钟的睡眠时间。通过改变睡眠选项可能节省的费用可能是纳秒或微秒。

我每次都更喜欢后一种风格,但是如果你拥有前者,而且要改变它会花费你很多,“提高性能”并不是一个特别好的理由。

编辑 re:8000个帖子

8000个线程非常多;我可能会移动到计划执行程序,以便您可以控制系统上的负载量。关于不同唤醒时间的观点需要注意,尽管我认为更大的风险是线程踩踏,所有线程都在沉睡,然后紧密连续醒来并争夺所有系统资源。

我会花时间将这些全部放在一个固定的线程池调度执行器中。只有最多有限资源可用的同时运行(例如,#cores或#IO路径)加上一些可以获取任何slop。这将以延迟为代价为您提供良好的吞吐量。

使用Thread.sleep()方法很难控制正在发生的事情,并且您可能会失去吞吐量延迟。

如果您需要更详细的建议,您可能需要更详细地描述您要做的事情。

答案 1 :(得分:2)

有不同的场景,

  1. Timer创建一个不断更新的任务队列。 Timer完成后,可能不会立即进行垃圾回收。因此,创建更多Timers只会在堆上添加更多对象。 Thread.sleep()只会暂停线程,因此内存开销会非常低
  2. Timer / TimerTask还会考虑任务的执行时间,因此会更准确一些。它更好地处理多线程问题(例如避免死锁等)。
  3. 如果你的线程获得异常并被杀死,那就是一个问题。但TimerTask会照顾它。无论以前的运行失败,它都会运行
  4. TimerTask的优点在于它更好地表达了您的意图(即代码可读性),并且已经实现了cancel()功能。
  5. 参考来自here

答案 2 :(得分:1)

由于您没有提及Java版本,因此可能会发生变化。

我从Java的源代码中回忆一下,最重要的区别在于内部编写的内容。

对于 Sun Java 1.6 ,如果您使用第二种方法,本机代码也会引入等待并通知对系统的调用。所以,在某种程度上更有线程效率和CPU友好性。

但是你再次放松了控制,你的代码变得更加难以预测 - 考虑你想要睡10秒钟。

所以,如果你想要更多的可预测性 - 你肯定可以选择1。

另外,在旁注中,在遗留系统中遇到类似这样的事情 - 现在有80%的可能性有更好的方法 - 但是神奇的数字是有原因的(剩下的20%)所以,改变风险自负:)

答案 3 :(得分:0)

您说过您正在“大型...高负载环境”中运行,因此,如果我正确理解您的话,您将有许多此类线程同时处于休眠状态,就像您的代码示例一样。重用线程比杀死并创建一个新线程要花费更少的CPU时间,并且重构可能使您可以重用线程。

您可以使用corePoolSize大于1的ScheduledThreadPoolExecutor创建线程池,然后在该线程池上调用scheduleWithFixedDelay时,如果有线程可用重用。

此更改可能会降低CPU利用率,因为正在重用线程而不是销毁和创建线程,但是减少的程度将取决于它们正在执行的任务,池中的线程数等。内存使用率也会降低如果某些任务重叠,则关闭,因为一次空闲的线程较少。