java - Java线程: 'join' froze my program

标签 java multithreading freeze

我的程序如下所示:

class Prog
 {
 BufferedImage offscreen;
 KindOfDatabase db;
 MyThread thread;

 class MyThread extends Thread
    {
    volatile boolean abort=false;
    long lastUpdated;
    public void run()
        {
        try
          {
          KindOfCursor c = db.iterator();
          while(c.getNext())
            {
            if(abort) break;
            //fill a histogram with the data,
            // calls SwingUtilities.invokeAndWait every 500ms to
            //do something with offscreen and update a JPanel
            }
          catch(Exception err)
            {
            err.printStackTrace();
            }
          finally
            {
            c.close();
            }
        }
    }

  void stopThread()
       {
       if(thread!=null)
          {
          thread.abort=true;
          thread.join();
          thread=null;
          }
       }
  void startThread()
      {
      stopThread();
      thread=new MyThread();
      thread.start();
      }
(....)
 }

1)该程序在我的计算机上运行良好。但是,当我运行它时,它抛出了“ssh -X remote.host.org”连接,运行非常缓慢,并且在调用thread.join()时程序被冻结。我将“join”替换为“interrupt()”,并且程序不再冻结。为什么 ?我应该担心,在调用interrupt()时,未调用关闭迭代器的“finally”语句吗?

2)我应该使用'Thread.isInterrupted()'而不是 boolean 'abort'吗?

谢谢

更新:我的中止标志被标记为volatile。不更改冻结状态。

最佳答案

Thread.join旨在“冻结”您的线程!

当您调用join时,当前线程将暂停,直到其加入的线程退出为止。在您的情况下,这种冻结之所以发生是因为MyThread实例未及时退出。

此处可能会困扰您的一件事-,您需要将中止变量声明为volatile,以便其他线程能够可靠地看到更改。由于您没有这样做,因此MyThread完全有可能在中止变量始终为true的情况下看到其缓存版本。有一个简短的描述here

编辑:我之前错过了关于它在本地但不在远程计算机上工作的声明。实际上,这在并发相关的竞争条件中并不少见,因为它们可能会或可能不会显示,这取决于各种因素,例如硬件设置,机器上的负载等。在这种情况下,例如,如果您的本地机器只有一个物理CPU/核心,则您的错误代码可能会正常运行;尽管只有一个CPU缓存,所以另一个线程很可能“看到”主线程更改了abort标志,即使它没有显式标记为volatile。现在将其移至多核计算机上,如果将线程调度到单独的内核上,则它们将使用单独的缓存,并且突然之间将看不到对非 volatile 缓存变量的更改。

这就是为什么它是非常重要的,了解并发的后果和什么有保障的,因为故障不会表现以一致的方式。

更新 react :如果在异常终止时该方法仍然不起作用,则听起来很像MyThread没有足够频繁地检查变量。请记住,它只会“通知”中止标志已经直接从你的那种-的光标拉另一种-的行后进行设置。如果它可能是一个单一的元素相对于直方图的处理可能需要很长的时间,那么它当然不会在这个时候看到国旗。

您可能只需要更频繁地检查中止标志。您说您每500毫秒调用一次invokeAndWait;您应该在每次调用前检查中止标志,因此必须等待最多500ms才能终止线程!浏览一下代码的这一部分,看看是否有任何内部循环可以修改为更像while (... && !abort)

另一种垂直的方法是也开始中断线程。特别是SwingUtilities.invokeAndWait是可中断的,因此,如果您在thread.interrupt()方法中调用stopThread(),则invokeAndWait调用将很快终止(通过引发InterruptedException),而不必等到它正常完成后,代码才有机会检查再次中止标志。这样做还有一个好处,就是如果其他一些可中断的操作花费很长时间才能完成,它也会立即返回。 (在这种情况下,您可能希望在代码的处理位中显式捕获InterruptedException;您实际上并不需要做任何事情来处理它,只需将它作为唤醒并再次检查标志的标志即可请阅读此出色的Developerworks article,以获取有关处理InterruptedExceptions的更多信息。

最后,如果您仍然遇到问题,那么一些好的老式println调试会有所帮助。如果您在每次检查中止标志时都将MyThread打印到控制台(或者可能是一些日志文件),您将能够查看问题是否是由于MyThread本身“冻结”引起的。在这种情况下,它将永远不会退出,并且调用线程将永远不会从join()调用返回。向下移动中止标志的检查可能会对此有所帮助。

关于java - Java线程: 'join' froze my program,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1530088/

相关文章:

java - Linux下查找一个java进程的pid

Python:ftplib 在传输结束时挂起

python - Ansible 由于其构建的 ssh 问题而挂起

python - python freeze 可以在 64 位 linux 上编译 32 位二进制文​​件吗

java - 如何使用 jackson CsvMapper 或其他 csv 解析器解析 CSV 字符串中的列?

java - 使用 JSON-Simple 的 JSON 解析不起作用

java - 非常不寻常的舍入

java - Tomcat java.lang.OutOfMemoryError : GC overhead limit exceeded 错误

c - 在线程中递增和返回整数是原子操作吗?

c++ - 删除 Windows 库依赖项