java Thread.sleep() 挂了?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6749159/
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
Thread.sleep() is hung?
提问by andersonbd1
Here's my simple code to loop every second (doesn't need to be exact) and kick off a job if necessary:
这是我每秒循环的简单代码(不需要精确)并在必要时开始工作:
while (true) {
// check db for new jobs and
// kick off thread if necessary
try {
Thread.sleep(1000);
} catch(Throwable t) {
LOG.error("", t);
}
}
This code has worked fine for several months. Just yesterday we started having problems where one of our servers seems to be hung in the Thread.sleep(1000) method. IOW - it's been over a day and the Thread.sleep hasn't returned. I started up jconsole and get this info about the thread.
这段代码已经运行了好几个月。 就在昨天,我们开始遇到问题,其中一台服务器似乎挂在 Thread.sleep(1000) 方法中。IOW - 一天过去了,Thread.sleep 还没有回来。我启动了 jconsole 并获取了有关该线程的信息。
Name: Thread-3
State: TIMED_WAITING
Total blocked: 2 Total waited: 2,820
Stack trace:
java.lang.Thread.sleep(Native Method)
xc.mst.scheduling.Scheduler.run(Scheduler.java:400)
java.lang.Thread.run(Thread.java:662)
Scheduler.java:400 is the Thread.sleep line above. The jconsole output doesn't increment "Total waited" every second as I'd expect. In fact it doesn't change at all. I even shut down jconsole and started it back up in the hopes that maybe that would force a refresh, but only got the same numbers again. I don't know what other explanation there could be besides that the jvm has incorrectly hung on the sleep command. In my years, though, I've had so few problems with the jvm that I assume it must be an oversight on my part.
Scheduler.java:400 是上面的 Thread.sleep 行。jconsole 输出不会像我期望的那样每秒钟增加“等待的总数”。事实上,它根本没有改变。我什至关闭了 jconsole 并重新启动它,希望这可能会强制刷新,但只能再次获得相同的数字。除了 jvm 错误地挂在 sleep 命令上之外,我不知道还有什么其他解释。然而,在我这些年里,我在 jvm 方面遇到的问题很少,我认为这一定是我的疏忽。
note: The other thing to note is that no other thread is active.IOW - the cpu is nearly idle. I read somewhere that Thread.sleep could be legitimately starved if another thread was active, but that isn't the case here.
注意:另一件要注意的事情是没有其他线程处于活动状态。IOW - cpu 几乎空闲。我在某处读到如果另一个线程处于活动状态,Thread.sleep 可能会合法地饿死,但这里的情况并非如此。
solaris version:
Solaris 版本:
$ uname -a
SunOS xcmst 5.10 Generic_141415-08 i86pc i386 i86pc
java version:
爪哇版:
$ java -version
java version "1.6.0_26"
Java(TM) SE Runtime Environment (build 1.6.0_26-b03)
Java HotSpot(TM) Server VM (build 20.1-b02, mixed mode)
回答by Shaded
In addition to what bdonlan mentioned you may want to look into ScheduledThreadPoolExecutor. I work on a very similar type of project and this object has made my life easier, thanks to this little snippet.
除了 bdonlan 提到的内容,您可能还想查看ScheduledThreadPoolExecutor。我从事一个非常相似类型的项目,多亏了这个小片段,这个对象让我的生活更轻松。
ScheduleAtFixedRate
以固定速率调度
If any execution of this task takes longer than its period, then subsequent executions may start late, but will not concurrently execute.
如果此任务的任何执行时间超过其周期,则后续执行可能会延迟开始,但不会并发执行。
I hope this helps!
我希望这有帮助!
回答by user541686
Are you dependingon the system tick count to increase monotonically?
您是否依赖系统滴答计数单调增加?
From what I've heard from someone experienced, it (occasionally) happens that the system tick goes backwards by one or two ticks. I haven't experienced it myself yet, but if you're depending on this, might this explain what's happening?
根据我从有经验的人那里听到的,系统滴答(偶尔)会倒退一两个滴答。我自己还没有经历过,但是如果您依赖于此,这是否可以解释正在发生的事情?
Edit:
编辑:
When I said System.currentTimeMillis()
, I believe I was mistaken. I thought that System.currentTimeMillis()
is similar to Windows' GetTickCount()
function (i.e. it is measures a time that is independentof the system time), but in fact, that does not seem to be the case. So of courseit can change, but that was notmy point: apparently, tick counts measured by the system timer can alsogo backwards by a tick or two, even ignoring system time changes. Not sure if that helps, but thanks to Raedwald for pointing out the system time change possibility, since that's not what I meant.
当我说System.currentTimeMillis()
,我相信我错了。我以为这System.currentTimeMillis()
类似于Windows的GetTickCount()
功能(即它是测量独立于系统时间的时间),但实际上似乎并非如此。所以当然它可以改变,但这不是我的观点:显然,系统计时器测量的滴答计数也可以倒退一两个滴答,甚至忽略系统时间的变化。不确定这是否有帮助,但感谢 Raedwald 指出系统时间更改的可能性,因为那不是我的意思。
回答by jtoberon
I know that you looked in jconsole, but it might be useful to send signal 3 to the process (that is, kill -3) and post more of the resulting thread dump here. Or, if you really want to get into the details, then you might consider taking one or more pstack/jstack dumps of the hung process in quick succession in order to show where the threads really are. Information is available online about how to correlate this information with a java thread dump.
我知道您查看了 jconsole,但是将信号 3 发送到进程(即 kill -3)并在此处发布更多结果线程转储可能很有用。或者,如果您真的想深入了解细节,那么您可以考虑快速连续获取一个或多个挂起进程的 pstack/jstack 转储,以显示线程的真正位置。有关如何将此信息与 Java 线程转储相关联的信息可在线获取。
Also, by "one of our servers," are you saying that the problem is reproducible on one server, but it never occurs on other servers? This indicates a problem with that one server. Check that everything is the same across your servers and that there are no issues on that hardware in particular.
另外,通过“我们的一台服务器”,您是说问题可以在一台服务器上重现,但在其他服务器上从未发生?这表明该服务器存在问题。检查您的服务器上的所有内容是否相同,并且该硬件没有特别的问题。
Finally, this might not be a java problem per se. Thread.sleep(long) is a native method (maps directly onto the underlying operating system's thread management), so check that your OS is up to date.
最后,这本身可能不是 Java 问题。Thread.sleep(long) 是本机方法(直接映射到底层操作系统的线程管理),因此请检查您的操作系统是否是最新的。
回答by Kowser
Have you considered using Timer& TimerTask.
Here is simple snippet which might help.
这是可能有帮助的简单片段。
import java.util.Calendar;
import java.util.Timer;
import java.util.TimerTask;
public class Example {
public static void main(String args[]) {
Timer timer = new Timer();
TimerTask task = new TimerTask() {
@Override
public void run() {
Calendar instance = Calendar.getInstance();
System.out.println("time: " + instance.getTime() + " : " + instance.getTimeInMillis());
// check db for new jobs and
// kick off thread if necessary
}
};
int startingDelay = 0; // timer task will be started after startingDelay
int period = 1000; // you are using it as sleeping time in your code
timer.scheduleAtFixedRate(task, startingDelay, period);
}
}
EDIT
编辑
According to the discussions I have studied, Thread.sleep() is the sign of poorly designed code.
Reasons are
根据我研究过的讨论,Thread.sleep() is the sign of poorly designed code.
原因是
- ...The thread does not lose ownership of any monitors (from documentation).
- Blocks the thread from execution.
- And obviously it does not give any guarantee, that execution will start after sleeping time.
- To me, it is so much primitive to use Thread.sleep(). There is a whole package dedicated to concurrency.
- ...该线程不会失去任何监视器的所有权(来自文档)。
- 阻止线程执行。
- 显然它不提供任何保证,即执行将在休眠时间后开始。
- 对我来说,使用 Thread.sleep() 太原始了。有一整套专用于并发的软件包。
Which one is better instead of Thread.sleep()? Which raises another question. I would suggest you to have a look in Concurrencychapter from the book Effective Java
.
哪个比 Thread.sleep() 更好?这就提出了另一个问题。我建议你看看书中的并发章节Effective Java
。
回答by Augustus Thoo
Thread.sleep()is not a good practice in Java programming. Just Google "Is Thread.sleep() bad?" and you will see my point.
Thread.sleep()在 Java 编程中不是一个好习惯。只是谷歌“Thread.sleep() 不好吗?” 你会明白我的观点。
Firstly, it makes the current Thread inaccessible by other parts of the program especially if it is multi-threaded. Maybe that is why you are experiencing the hang.
首先,它使程序的其他部分无法访问当前线程,尤其是在它是多线程的情况下。也许这就是您遇到挂起的原因。
Secondly, it would be catastrophic if the current thread is EDT (Event Dispatch Thread) and the application has Swing GUI.
其次,如果当前线程是 EDT(Event Dispatch Thread)并且应用程序具有 Swing GUI,那将是灾难性的。
A better alternative would be Object.wait():
更好的选择是Object.wait():
final Object LOCK = new Object();
final long SLEEP = 1000;
public void run() {
while (true) {
// check db for new jobs and
// kick off thread if necessary
try {
synchronize (LOCK) {
LOCK.wait(SLEEP);
}
} catch (InterruptedException e) {
// usually interrupted by other threads e.g. during program shutdown
break;
}
}
}
回答by Ben Xu
maybe you can try another tool other than Jconsole to first confirm that it is block in the sleep api.
也许您可以尝试使用 Jconsole 以外的其他工具来首先确认它在 sleep api 中是块。
For example, manually try using jstack to print it to file for many times and check the result.
例如,手动尝试使用jstack多次打印到文件并检查结果。
Or use a better tool, such as Youkit (commercail) if your org has its license to profile the application in depth, or remote debug (maybe can not in production)
或者使用更好的工具,例如 Youkit (commercail),如果您的组织拥有深入分析应用程序的许可证,或者远程调试(可能无法在生产中)
OR You can check whether the "// check db for new jobs " code is run during. by checking loggings, or profile, or any other method depends on your application........ If the check db is very quick, and then sleep 1 seconds, if is very likely that you always see sleep in stack trace just because the compared probability....
或者您可以检查“// check db for new jobs”代码是否在运行期间。通过检查日志记录或配置文件或任何其他方法取决于您的应用程序........如果检查数据库非常快,然后休眠 1 秒钟,如果很可能您总是在堆栈跟踪中看到休眠只是因为比较概率....