调用Thread.getAllStackTraces()时发生挂起

时间:2017-09-26 22:06:28

标签: java multithreading performance hang

我正在运行以下代码来显示我的程序的正在运行的线程

public void printTasks() {
    System.out.println("get threads start");
    for (Thread thread : Thread.getAllStackTraces().keySet()) {
        //This block filters the non-java threads running
        if (!thread.getThreadGroup().getName().equals("system")) {
            System.out.println("hello");
        }
    }
    System.out.println("get threads end");
}

问题在于,有时代码会在打印后立即挂起"让线程启动",我怀疑挂起发生在这一行" Thread.getAllStackTraces()"

注意:我的程序使用线程执行一组任务,因此,它会创建大约70个线程并且挂起是间歇性的,我称之为此方法的每6或7次中只有1个出现问题

我的问题是:

  • 这是一个已知问题吗?
  • 有没有办法防止这种行为?
  • 是否有更安全的方法列出正在运行的线程?

编辑:我使用java 1.8,问题发生在Linux OEL和Windows Server中,在这两种情况下都是间歇性的,软件作为独立的桌面应用程序运行

提前谢谢

1 个答案:

答案 0 :(得分:0)

我刚刚发现了问题所在(至少这是我的假设)。

用于检索正在运行的线程的代码遇到了竞争条件。

我的程序正在创建的线程不断变化,有些线程会在非常短的时间内(1秒或更短的时间内)结束

函数Thread.getAllStackTraces()返回 HashMap 的线程和堆栈跟踪(第a行),然后在下一行(第b行)我试图获取线程的组名

 for (Thread thread : Thread.getAllStackTraces().keySet()) { <--- a
     if (!thread.getThreadGroup().getName().equals("system")) { <--- b

但线程持续得很少,以至于在第二行到达之前消失了,因此我最终尝试使用无效键从地图中获取值(这是竞争条件)

注意:如果您以前从未体验过这种情况,当您尝试读取不存在的HashMap的值时,您可能最终会等待结果

<强>解决方案

在尝试读取其属性

之前,确保线程仍然存在
public void printTasks() {
    System.out.println("get threads start");
    for (Thread thread : Thread.getAllStackTraces().keySet()) {
        //This block filters the non-java threads running
        if (Thread.getAllStackTraces().containsKey(thread) && //<--new line here
            thread.getThreadGroup().getName().equals("system")) {
            System.out.println("hello");
        }
    }
    System.out.println("get threads end");
}

第二种方法是尝试获取getAllStackTraces()内容的快照以读取不可变对象

欢迎更好的解决方案,希望这有助于某人