1

这是我的第一个问题,
所以我有一个非常奇怪的问题。
下面是我的问题...

我编写了非常简单的方法,将一些文本写入文件。
当然它在我的机器上运行良好(XP、4CPU、jdk1.5.0_17[SUN])
但它有时会在运行服务器上冻结
(Linux Accounting240 2.4.20-8smp、4CPU、jdk1.5.0_22[SUN])。

杀死 -3 不起作用。
ctrl + \ 不起作用。

所以,我不能给你看线程转储。

它冻结得很好..当我用这种方法写一些 Thread.sleep(XX) 时,问题就解决了(?)...
sleep(XX) break... 今天又发生了 Thread.sleep(XX) ...

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

PS
linux 发行版:Red Hat Linux 3.2.2-5
命令:java -cp。吨

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

3 回答 3

2

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

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

于 2009-12-09T08:40:49.273 回答
0

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

每隔几秒钟执行几次,然后比较线程转储。如果它们总是相同,那么看起来您的应用程序已死锁;转储的第一行将准确显示线程阻塞的位置(这将提供一个很好的线索,当您查看该行代码时,它们被阻塞在哪些资源上)。

另一方面,如果线程转储不时发生变化,则程序并未严格死锁,但看起来它正在无限循环中运行 - 可能您的循环条件之一未正确声明,因此线程永远不会退出或类似的东西. 再次,查看线程转储集以了解每个线程在哪个代码区域循环,这将使您了解永远不会评估退出条件的循环条件。

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

于 2009-12-09T09:18:16.520 回答
0

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

这可能是其他问题的迹象。我建议:

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

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

于 2009-12-09T11:13:50.560 回答