Pie*_*rre 1 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();
}
(....)
}
Run Code Online (Sandbox Code Playgroud)
1)该程序在我的计算机上运行良好.但是当我运行它时,抛出'ssh -X remote.host.org'连接,一切都很慢,并且在调用thread.join()时程序被冻结.我用'interrupt()'替换了'join',程序不再被冻结了.为什么?我是否应该担心,当调用interrupt()时,没有调用关闭迭代器的'finally'语句?
2)我应该使用'Thread.isInterrupted()'而不是我的布尔'abort'吗?
谢谢
更新:我的中止标志标有volatile.不改变冷冻状态.
Thread.join意味着"冻结"你的线程!
当您调用join时,当前线程将暂停,直到它正在加入的线程退出.在您的情况下,这种冻结正在发生,因为MyThread实例没有及时退出.
有一件事可能会在这里咬你 - 你需要声明中止变量,volatile以便其他线程能够可靠地看到变化.由于你没有这样做,你的MyThread完全可以看到中止变量的缓存版本,它始终是真的.有它的一个简短的描述在这里.
编辑:我之前错过了你的声明,关于它在本地工作但不在远程机器上.对于与并发相关的竞争条件,这实际上并不罕见,因为它们可能会或可能不会显示,具体取决于各种因素,例如硬件设置,机器上的负载等.例如,如果您的本地计算机只有一个物理CPU /核心然后您的错误代码可能会正常运行; 只有一个CPU缓存,所以另一个线程可能"看到"主线程更改abort标志,即使它没有明确标记为volatile.现在将其移至多核机器,如果线程被调度到不同的内核,它们将使用单独的缓存,并且突然间不会看到对非易失性缓存变量的更改.
这就是为什么理解并发性的后果以及确切的保证非常重要的原因,因为失败不会以一致的方式表现出来.
更新反应:如果在中止易失性时仍然无法正常工作,听起来很像MyThread是不经常检查变量.请记住,它只会"注意"在从您的游标类型中拉出另一种行之后,直接设置了中止标志.如果单个元素相对于直方图的处理可能需要很长时间,那么当然在此期间它不会看到标记.
您可能只需要更频繁地检查中止标志.你说你invokeAndWait每隔500毫秒打电话; 你应该在每次调用之前检查你的中止标志,所以你必须等待最多500ms才能终止线程!仔细查看代码的这一部分,看看是否有任何内部循环可以修改,看起来更像while (... && !abort).
另一种垂直方法是开始中断线程.SwingUtilities.invokeAndWait特别是可中断的,所以如果你调用thread.interrupt()你的stopThread()方法,那么invokeAndWait调用将很快终止(通过抛出InterruptedException),而不是你必须等到它正常完成才能让代码有机会检查中止再次举旗.这样做的另一个好处是,如果其他一些可中断操作需要很长时间才能完成,它也会立即返回.(在这种情况下,您可能希望在处理代码中明确捕获InterruptedException;您本身并不需要做任何事情来处理它,只需将其作为唤醒的标志并再次检查标志阅读这篇优秀的Developerworks文章,了解有关处理InterruptedExceptions的更多信息.
最后,如果你仍然遇到问题,那么一些好的老式println调试将有所帮助.如果MyThread每次检查中止标志时都打印到控制台(或可能是某些日志文件),您将能够看到问题是否是由于MyThread本身"冻结"造成的; 因为在这种情况下它将永远不会退出,并且调用线程将永远不会从join()调用返回.将检查中止标志向下移动可能有助于此.