Thread.sleep()挂了吗?

时间:2011-07-19 14:49:29

标签: java sleep

这是我的简单代码,每秒循环(不需要精确),并在必要时开始工作:

while (true) {
  // check db for new jobs and 
  // kick off thread if necessary
  try {
    Thread.sleep(1000);
  } catch(Throwable t) {
    LOG.error("", t);
  }
}

这段代码已经好几个月了。 就在昨天,我们开始出现问题,其中一个服务器似乎挂在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是上面的Thread.sleep行。按照我的预期,jconsole输出不会每秒增加“Total wait”。事实上,它根本没有变化。我甚至关闭了jconsole并重新启动它,希望可能会强制刷新,但只会再次获得相同的数字。我不知道除了jvm错误地挂在sleep命令上之外还有什么其他的解释。然而,在我这些年里,我对jvm的问题很少,我认为这一定是我的疏忽。

注意:另外需要注意的是没有其他线程处于活动状态。 IOW - cpu几乎处于空闲状态。我在某处读到如果另一个线程处于活动状态,Thread.sleep可能会被合法地饿死,但这不是这种情况。

solaris版本:

$ uname -a
SunOS xcmst 5.10 Generic_141415-08 i86pc i386 i86pc

java版:

$ 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)

6 个答案:

答案 0 :(得分:7)

除了bdonlan提到的内容之外,您可能还需要了解ScheduledThreadPoolExecutor。我在一个非常相似的项目类型上工作,这个对象让我的生活变得更轻松,感谢这个小片段。

ScheduleAtFixedRate

  

如果此任务的执行时间超过其周期,那么   后续处决可能会延迟,但不会同时执行   执行。

我希望这有帮助!

答案 1 :(得分:5)

依赖对系统滴答计数进行单调增加吗?

根据我从有经验的人那里听到的,它(偶尔)会发生系统滴答,倒退一两个滴答。我自己还没有经历过,但如果你依赖于此,这可能会解释发生了什么吗?

编辑:

当我说System.currentTimeMillis()时,我相信我错了。我认为System.currentTimeMillis()类似于Windows'GetTickCount()函数(即它测量系统时间独立的时间),但事实上,这似乎不是是这样的。那么当然它可以改变,但那是我的观点:显然,系统计时器测量的滴答计数可以倒退一个滴答或两次,甚至忽略系统时间的变化。不确定这是否有帮助,但感谢Raedwald指出系统时间变化的可能性,因为那不是我的意思。

答案 2 :(得分:3)

我知道您查看了jconsole,但将信号3发送到进程(即kill -3)并在此处发布更多结果线程转储可能很有用。或者,如果您真的想了解详细信息,那么您可以考虑快速连续地对挂起进程执行一个或多个pstack / jstack转储,以显示线程的确实位置。有关如何将此信息与java线程转储相关联的信息可在线获取。

此外,通过“我们的一台服务器”,您是说这个问题在一台服务器上是可重现的,但它永远不会在其他服务器上发生?这表明该服务器存在问题。检查服务器上的所有内容是否相同,特别是该硬件上没有任何问题。

最后,这本身可能不是java问题。 Thread.sleep(long)是一种本机方法(直接映射到底层操作系统的线程管理),因此请检查您的操作系统是否是最新的。

答案 3 :(得分:2)

您是否考虑过使用Timer& TimerTask

以下是可能有用的简单代码段。

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);
    }

}

修改

根据我所研究的讨论,Thread.sleep() is the sign of poorly designed code.原因是

  • ...线程不会失去任何监视器的所有权(来自文档)。
  • 阻止线程执行。
  • 显然它没有给出任何保证,执行将在休眠时间后开始。
  • 对我来说,使用Thread.sleep()非常原始。有一整套专用于concurrency

哪一个更好而不是Thread.sleep()?这提出了另一个问题。我建议您查看本书Effective Java并发一章。

答案 4 :(得分:1)

Thread.sleep()在Java编程中不是一个好习惯。只是Google“Thread.sleep()是不是很糟糕?”你会看到我的观点。

首先,它使程序的其他部分无法访问当前的Thread,特别是如果它是多线程的。也许这就是你遇到困难的原因。

其次,如果当前线程是EDT(事件调度线程)并且应用程序具有Swing GUI,那将是灾难性的。

更好的选择是 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;
    }

  }
}

答案 5 :(得分:0)

也许你可以尝试除Jconsole之外的其他工具来首先确认它是睡眠api中的阻塞。

例如,手动尝试使用jstack将其多次打印到文件并检查结果。

或者使用更好的工具,例如Youkit(commercail),如果您的组织有权深入分析应用程序,或远程调试(可能无法生产)

或者您可以检查是否在运行期间运行“// check db for new jobs”代码。通过检查记录,或配置文件,或任何其他方法取决于您的应用程序........如果检查db非常快,然后睡1秒,如果你很可能总是看到堆栈跟踪睡眠只是因为比较概率......