Java Thread.sleep()与Executor.scheduleWithFixedDelay()的比较

Java Thread.sleep()与Executor.scheduleWithFixedDelay()的比较,java,multithreading,thread-sleep,scheduledexecutorservice,Java,Multithreading,Thread Sleep,Scheduledexecutorservice,目标:每隔一段时间执行一次特定代码 问题:就绩效而言,以下各项之间是否存在显著差异: while(true) { execute(); Thread.sleep(10 * 1000); } 及 ? 当然,后一种选择更符合犹太教。然而,我想知道我是否应该开始一个名为“花几天时间重构遗留代码,告别Thread.sleep()”的冒险 更新: 此代码在超级/超大/超高负载环境中运行。您正在处理以数十秒为单位的睡眠时间。在这里更改睡眠选项可能节省纳秒或微秒 我每次都更喜欢后一种风格,但

目标:每隔一段时间执行一次特定代码

问题:就绩效而言,以下各项之间是否存在显著差异:

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

?

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

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

您正在处理以数十秒为单位的睡眠时间。在这里更改睡眠选项可能节省纳秒或微秒

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

编辑:8000个线程

8000个线程是一个可怕的数目;我可能会移动到计划执行器,以便您可以控制系统上的负载量。你关于不同唤醒时间的观点是需要注意的,尽管我认为更大的风险是线程蜂拥而至——所有线程都处于睡眠状态,然后依次醒来,并争夺所有系统资源

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

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


如果您需要更详细的建议,您可能需要更详细地描述您正在尝试执行的操作。

因为您没有提到Java版本,所以情况可能会发生变化

正如我从Java源代码中回忆到的,主要的区别在于内部编写的方式

对于Sun Java 1.6而言,如果使用第二种方法,则本机代码还将引入对系统的等待和通知调用。因此,在某种程度上,线程效率更高,CPU更友好

但是,您再次松开控件,它对代码变得更加不可预测——假设您想休眠10秒。 因此,如果你想要更多的可预测性,你当然可以选择选项1


另外,另一方面,在传统系统中,当您遇到这样的事情时,80%的机会现在有更好的方法来做,但神奇的数字存在是有原因的(其余20%),因此,更改它要自担风险:)

有不同的场景

  • 计时器创建一个不断更新的任务队列。计时器完成后,可能不会立即对其进行垃圾收集。因此,创建更多计时器只会将更多对象添加到堆中。sleep()只暂停线程,因此内存开销非常低
  • Timer/TimerTask还考虑了任务的执行时间,因此会更加精确。它可以更好地处理多线程问题(如避免死锁等)
  • 如果线程发生异常并被终止,这就是一个问题。但TimerTask会处理好的。无论上一次运行是否失败,它都将运行
  • TimerTask的优点是它能更好地表达您的意图(即代码可读性),并且已经实现了cancel()特性

  • 参考资料取自

    您说过您正在“超大…高负载环境”中运行,所以如果我理解正确,您有许多这样的线程同时休眠,就像您的代码示例一样。重用线程所需的CPU时间比杀死并创建一个新线程所需的CPU时间要少,重构可能允许重用线程

    您可以使用
    corePoolSize
    大于1的创建线程池。然后,当您调用该线程池时,如果一个线程可用,它将被重用


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

    我认为两者都是相同的,
    scheduleWithFixedDelay
    封装的睡眠调用。@Quoi:它们实际上不一样,因为计划执行者可以执行许多计划任务,并在少于任务数量的线程中运行它们。如果你只是使用睡眠,你必须为你“安排”的每个任务都有一个线程。你为什么要询问睡眠操作的性能?@Dan:嗯,我在线程转储中看到的是:java.lang.thread.State:TIMED_WAITING(睡眠)VS java.lang.thread.State:TIMED_WAITING(停车)。这显然是有区别的,可能也是性能上的差异。我担心的是我们有8000个线程,休眠线程的优先级可能很低,以至于它们执行时会有很大的延迟,这可能会导致GC出现附带问题。
    executor.scheduleWithFixedDelay(runnableWithoutSleep, 0, 10, TimeUnit.SECONDS);