java进程在linux上被冻结(?)

时间:2009-12-09 08:01:26

标签: java linux file multiprocessor

这是我关于S.O.的第一个问题 我有一个非常奇怪的问题 以下是我的问题...

我写了一个非常简单的方法,将一些文本写入文件 当然它适用于我的机器(XP, 4CPU ,jdk1.5.0_17 [SUN])
somtimes 在操作服务器上冻结了 (Linux Accounting240 2.4.20-8smp, 4CPU ,jdk1.5.0_22 [SUN])。

kill -3不起作用。
ctrl + \不起作用。

所以,我无法向你展示线程转储。

冻结得很好.. 当我在这个方法上写一些Thread.sleep(XX)时,问题很顺利(?)...
睡觉(XX)休息......今天又发生了Thread.sleep(XX)......

你知道这个问题吗? 你对此有一些解决方案吗? 谢谢。 : - )

P.S。
linux发行版:Red Hat Linux 3.2.2-5
命令:java -cp。 T

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.text.SimpleDateFormat;
import java.util.Date;

public class T {
private BufferedWriter writer = null;

private void log(String log) {
    try {
        if (writer == null) {
            File logFile = new File("test.log");
            writer = new BufferedWriter(new OutputStreamWriter(
                    new FileOutputStream(logFile, true)));
        }
        writer.write(new SimpleDateFormat("[yyyy-MM-dd HH:mm:ss] ")
                .format(new Date()));
        writer.write("[" + log + "]" + "\n");
        writer.flush();

         /*
                         *  this is ad hoc solution ???
                         */
        //Thread.sleep(10);
    } catch (Exception e) {
        e.printStackTrace();
    } finally {         
    }

}

public void test() {
    long startTime = System.currentTimeMillis();

    while (true) {
        log(String.valueOf(System.currentTimeMillis()));
        System.out.println(System.currentTimeMillis());
        try {
            //Thread.sleep((int) (Math.random() * 100));
        } catch (Exception e) {
            break;
        }

        if (System.currentTimeMillis() - startTime > 1000 * 5) {
            break;
        }
    }

    if (writer != null) {
        try {
            writer.close();
        } catch (Exception e) {
        }
    }
    System.out.println("OK");
}

public static void main(String[] args) {
    new T().test();
}
}

3 个答案:

答案 0 :(得分:2)

如果JVM没有响应kill -3,那么它不是你的程序,而是失败的JVM,这很糟糕,需要向Sun报告错误。

我注意到你正在运行2.4.20-8smp内核。这不是当前开源Linux发行版的典型内核,因此我建议您查看http://java.sun.com/j2se/1.5.0/system-configurations.html以查看是否要部署到支持的配置。如果没有,你应该让责任人知道这一点!

答案 1 :(得分:0)

第一步是获取程序在“冻结”时的位置的线程转储。如果这是在Java 6上,您可以默认将JVisualVM或JConsole连接到它,并从那里获取所有线程的堆栈跟踪。由于它是Java 5的,你应该能够使用jstack命令来获取线程转储(或者你可以用命令行选项来连接上述工具启用JMX,但我不认为这是值得的在这种情况下)。在所有情况下,从启动应用程序的控制台按Ctrl-Break也可能会产生线程转储,具体取决于环境。

相隔几秒钟几次,然后比较线程转储。如果它们总是相同的,那么看起来你的应用程序已陷入僵局;并且转储的顶行将准确显示线程阻塞的位置(这将提供一个非常好的线索,当您查看代码的那一行时,它们被阻止了哪些资源)。

在另一方面,如果线程转储不时改变,程序不严格的僵持状态,但看起来像它的无限循环中运行 - 也许是你的循环条件之一是不正确声明所以线程永远不会退出或某事那种再次,查看一组线程转储,以查看每个线程循环的代码区域,这将使您了解永远不会评估退出条件的循环条件。

如果此分析中的问题不明显,请回发转储,因为它可以帮助人们调试上述代码。

答案 2 :(得分:0)

我认为这是竞争条件。 while(true)将强制linux上的VM连续写入和刷新,Linux内核VM将尝试拦截这些调用并缓冲写入。这将使进程在等待系统调用完成时自旋循环;同时,它将由调度程序拾取并分配给另一个CPU(我可能在这里错了,所以)。新CPU将尝试获取资源上的锁,一切都将导致死锁。

这可能是未来其他问题的标志。我建议:

  • 首先,为清楚起见:将文件创建移到log()方法之外。这就是构造函数的用途。

  • 其次,你为什么要写这样的文件?你确定你的程序逻辑首先是有意义的吗?您是不是宁愿将日志消息写入容器(例如,一个ArrayList),并且每隔XX秒将其转储到一个单独的线程中的磁盘?现在,您将日志记录功能限制在磁盘速度上:您可能希望避免这种情况。