1

My program looked like this:

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) The program worked well on my computer. But when I ran it threw a 'ssh -X remote.host.org ' connection, all was very slow and the program was frozen when thread.join() was invoked. I replaced 'join' by 'interrupt()' and the program was not anymore frozen. Why ? Should I fear that, when interrupt() is called, the 'finally' statement closing the iterator was not invoked ?

2) should I use 'Thread.isInterrupted()' instead of my boolean 'abort' ?

Thanks

UPDATE: my abort flag was labelled with volatile. Doesn't change the frozen state.

4

4 回答 4

6

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

当你调用 join 时,当前线程将暂停,直到它加入的线程退出。在您的情况下,这种冻结正在发生,因为MyThread实例没有及时退出。

在这里可能会咬你的一件事 -你需要声明 abort 变量,volatile以便其他线程可以可靠地看到更改。由于您没有这样做,因此您的 MyThread 完全有可能看到 abort 变量的缓存版本,该版本始终为真。这里有一个简短的描述。

编辑:我错过了你之前关于它在本地工作但不在远程机器上的声明。这实际上与并发相关的竞争条件并不少见,因为它们可能会或可能不会出现,具体取决于硬件设置、机器负载等各种因素。在这种情况下,例如,如果您的本地机器只有一个物理 CPU/内核,那么您的错误代码可能会运行良好;只有一个 CPU 缓存,因此其他线程可能会“看到”主线程更改abort标志,即使它没有明确标记为易失性。现在将其转移到多核机器上,如果线程被调度到单独的内核上,它们将使用单独的缓存,并且突然之间不会看到对非易失性缓存变量的更改。

这就是为什么理解并发的后果以及确切的保证是非常重要的,因为失败不会以一致的方式表现出来。

更新反应:如果当 abort 是 volatile 时这仍然不起作用,这听起来很像MyThread没有足够频繁地检查变量。请记住,它只会“注意到”在从您的光标类型中拉出另一种类型的行之后直接设置了中止标志。如果对于直方图的单个元素的处理可能需要很长时间,那么在此期间它当然不会看到标志。

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

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

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

于 2009-10-07T07:50:00.493 回答
4

您在没有内存障碍的两个线程之间共享数据。如果您的主线程设置 abort = true,它可能会在本地设置 abort,但另一个处理器的本地缓存中已经为该字段设置了“false”。

volatile 关键字正是为此目的。

它可能在您的机器上工作,因为您只有一个处理器,但远程机器可能不行。

于 2009-10-07T07:49:02.557 回答
1

你的 KindOfCursor 是c.next()做什么的?它是否阻塞并等待更多数据?如果是这样,中断它可能会导致它停止等待并迅速返回。

于 2009-10-07T08:13:23.427 回答
0

你为什么不尝试调试它?当您在主线程中执行 thread.join() 命令时,它会等到线程完成。如果您的程序在此命令后被冻结,则可能线程未完成。原因可能是您无法连接到数据库,或者您从数据库(通过远程主机)获取数据的速度太慢。我认为您应该使用 log4j(或可以调试的东西)来调试它。

提示:您不应该使用变量布尔中止来控制线程。如果您在多线程环境中应用它是不安全的。您尝试用以下代码替换:

...in body thread
void run(){
    ...
    while(condition){
      if (interrupted()) 
          break;
    .....
}


...in body Prog class
void stopThread(){
    if(thread!=null)
    {
      thread.interrupt();
      thread.join();// i think you do not need this line, try it if you call interupt
      thread=null;
     }
}

希望你尽快解决。

于 2012-10-20T11:13:30.470 回答