java Thread.sleep() VS Executor.scheduleWithFixedDelay()

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13422125/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 12:39:16  来源:igfitidea点击:

Thread.sleep() VS Executor.scheduleWithFixedDelay()

javamultithreadingthread-sleepscheduledexecutorservice

提问by rudgirello

Goal: Execute certain code every once in a while.

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

Question: In terms of performance, is there a significant difference between:

问题:在性能方面,是否有显着差异:

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

and

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

?

?

Of course, the latter option is more kosher. Yet, I would like to know whether I should embark on an adventure called "Spend a few days refactoring legacy code to say goodbye to Thread.sleep()".

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

Update: This code runs in super/mega/hyper high-load environment.

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

采纳答案by Steven Schlansker

You're dealing with sleep times termed in tens of seconds. The possible savings by changing your sleep option here is likely nanoseconds or microseconds.

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

I'd prefer the latter style every time, but if you have the former and it's going to cost you a lot to change it, "improving performance" isn't a particularly good justification.

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

EDITre: 8000 threads

编辑回复:8000 个线程

8000 threads is an awful lot; I might move to the scheduled executor just so that you can control the amount of load put on your system. Your point about varying wakeup times is something to be aware of, although I would argue that the bigger risk is a stampede of threads all sleeping and then waking in close succession and competing for all the system resources.

8000 个线程非常多;我可能会转到预定的执行程序,以便您可以控制系统上的负载量。您关于不同唤醒时间的观点是需要注意的,尽管我认为更大的风险是线程全都处于休眠状态,然后连续醒来并竞争所有系统资源。

I would spend the time to throw these all in a fixed thread pool scheduled executor. Only have as many running concurrently as you have available of the most limited resource (for example, # cores, or # IO paths) plus a few to pick up any slop. This will give you good throughput at the expense of latency.

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

With the Thread.sleep()method it will be very hard to control what is going on, and you will likely lose out on both throughput andlatency.

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

If you need more detailed advice, you'll probably have to describe what you're trying to do in more detail.

如果您需要更详细的建议,您可能需要更详细地描述您想要做什么。

回答by Code_Mode

There are different scenarios,

有不同的场景,

  1. The Timer creates a queue of tasks that is continually updated. When the Timer is done, it may not be garbage collected immediately. So creating more Timers only adds more objects onto the heap. Thread.sleep() only pauses the thread, so memory overhead would be extremely low
  2. Timer/TimerTask also takes into account the execution time of your task, so it will be a bit more accurate. And it deals better with multithreading issues (such as avoiding deadlocks etc.).
  3. If you thread get exception and gets killed, that is a problem. But TimerTask will take care of it. It will run irrespective of failure in previous run
  4. The advantage of TimerTask is that it expresses your intention much better (i.e. code readability), and it already has the cancel() feature implemented.
  1. 计时器创建一个不断更新的任务队列。当 Timer 完成后,它可能不会立即被垃圾收集。所以创建更多的 Timer 只会在堆上添加更多的对象。Thread.sleep() 只暂停线程,所以内存开销会非常低
  2. Timer/TimerTask 也考虑了你的任务的执行时间,所以会准确一些。它可以更好地处理多线程问题(例如避免死锁等)。
  3. 如果您的线程获得异常并被杀死,那就是一个问题。但是 TimerTask 会处理它。无论上次运行是否失败,它都会运行
  4. TimerTask 的优点是它可以更好地表达您的意图(即代码可读性),并且它已经实现了 cancel() 功能。

Reference is taken from here

参考取自这里

回答by rock_win

Since you haven't mentioned the Java version, so, things might change.

由于您尚未提及 Java 版本,因此情况可能会发生变化。

As I recall from the source code of Java, the prime difference that comes is the way things are written internally.

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

For Sun Java 1.6if you use the second approach the native code also brings in the wait and notifycalls to the system. So, in a way more thread efficient and CPU friendly.

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

But then again you loose the control and it becomes more unpredictable for your code - consider you want to sleep for 10 seconds.

但是,您再次失去了控制权,并且您的代码变得更加不可预测 - 考虑一下您想要休眠 10 秒钟。

So, if you want more predictability - surely you can go with option 1.

所以,如果你想要更多的可预测性——当然你可以选择选项 1。

Also, on a side note, in the legacy systems when you encounter things like this - 80% chances there are now better ways of doing it- but the magic numbers are there for a reason(the rest 20%) so, change it at own risk :)

此外,附带说明一下,在遗留系统中,当您遇到这样的事情时 - 现在有 80% 的机会有更好的方法来做到这一点 - 但神奇数字的存在是有原因的(其余 20%)所以,在个人风险 :)

回答by Max

You said you are running in a "mega... high-load environment" so if I understand you correctly you have many such threads simultaneously sleeping like your code example. It takes less CPU time to reuse a thread than to kill and create a new one, and the refactoring may allow you to reuse threads.

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

You can create a thread pool by using a ScheduledThreadPoolExecutorwith a corePoolSizegreater than 1. Then when you call scheduleWithFixedDelayon that thread pool, if a thread is available it will be reused.

您可以通过使用创建一个线程池的ScheduledThreadPoolExecutor具有corePoolSize大于1。然后当你调用scheduleWithFixedDelay该线程池,如果一个线程可用,就可以重复使用。

This change may reduce CPU utilization as threads are being reused rather than destroyed and created, but the degree of reduction will depend on the tasks they're doing, the number of threads in the pool, etc. Memory usage will also go down if some of the tasks overlap since there will be less threads sitting idle at once.

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