【问题标题】:Impossible Java Memory Consistency Error不可能的 Java 内存一致性错误
【发布时间】:2014-11-09 18:18:14
【问题描述】:

首先,我不是以英语为母语的人,所以我为任何最终“怪异”的写作道歉。

我正在 Eclipse 上开发一个用于更新 Jpanel 的 Swing Java 应用程序。这个面板包含几个子面板,我不断切换面板的“模式”,而 MouseListener 发生了变化,因此它们对用户鼠标输入的响应方式略有不同。

无论应用程序做什么,它都会发生一个错误,对我来说似乎没有合乎逻辑的解释。在我的代码中的某个时刻,我尝试将面板更新为我所谓的中性模式。这发生在以下方法上:

//Guarded block (see http://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html)
private synchronized boolean waitsForUserSatisfactionAnswer()
{

    while(!userIndicatedSatisfaction) 
    {           
        try {
            wait();
        } catch (InterruptedException e) {}
    }

    userIndicatedSatisfaction = false; //reset for future new query

    getObjectSetVisualizationPanel().neutralMode();
    //getObjectSetVisualizationPanel().queryPatternMode();


    return userSatisfied;
}

此更新不起作用(对中性模式()的调用不符合预期)。然而,对 queryPatternMode() 的调用(在下面的行中注释)完美地工作。所以我决定复制 queryPatternMode() 的主体并将其粘贴到中性模式 () 的主体上,ECXATLY 相同!它仍然无法正常工作!

方法代码如下:

public void queryPatternMode()
    {
        System.out.println("Inside queryPatternMode!!!");
        System.out.println("panels.size(): " + panels.size());

        for (DigitalObjectPanel panel : panels) 
        {   
            System.out.println("Inside the loop!!!");
            panel.resetBehavior();
            panel.setQuerySelectionBehavior(gui);

            SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    panel.validate();
                }
            });

        }
    }

    public void neutralMode()
    {
        System.out.println("Inside neutralMode!!!");
        System.out.println("panels.size(): " + panels.size());

        for (DigitalObjectPanel panel : panels) 
        {   
            System.out.println("Inside the loop!!!");
            panel.resetBehavior();
            panel.setQuerySelectionBehavior(gui);

            SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    panel.validate();
                }
            });
        }

    }

发生的情况是,当我调用neutralMode() 时,“panels”集合恰好是空的(panels.size() 等于0)。但是,当我改为调用 queryPatternMode() 时,该集合恰好具有预期的大小(20 个面板)。但是这两个方法是相等的,而且都是从同一个地方调用的!!!

可能是什么???有什么可能的解释吗??

【问题讨论】:

  • 你是否在Event Dispatch Thread?上更新了 Swing 对象
  • panels的范围是什么?也许您将其隐藏在一种方法中,而不是另一种?你的 IDE 是怎么说的?用this.panels 替换panels 会改变什么吗?你有一个完整的功能示例我们可以尝试吗?
  • 您的代码看起来可能忽略了事件驱动编程的原则。通常你不应该不断地轮询诸如userIndicatedSatisfaction 之类的变量,而是使用侦听器或观察者模式,从而收到更改通知。按照其他人的建议,考虑创建并发布Minimal, Complete, and Verifiable Example Program
  • 是的,我在 EDT 上完成了所有的 ui 更新。 panel 是一个私有成员,两个方法都来自 panel 所属的同一个类。 IDE什么也没说,根本没有异常或错误,它只是在应用程序行为上。我只是尝试更改为 this.panels 并不起作用...
  • 该轮询是一个称为 Guarded block 的习语,由 oracle java 教程建议。毕竟,它似乎工作正常,while 条件检查是为了防止一些意外的唤醒。当我调用“模式”方法时会出现问题。具体的方法作用域是定义面板可见大小,根本没有意义!

标签: java multithreading swing memory


【解决方案1】:

这绝对看起来像一个同步问题。 您应该检查有多少线程正在访问集合“面板”。

幸运的是,它始终适用于 queryPatternMode(),而不适用于中性模式()。在另一个晴朗的日子里,它可能会有所不同。

【讨论】:

  • 感谢您的回答。起初我也认为是同步问题,所以我尝试了几个修复: - 声明面板列表 volatile - 同步两种方法 - 更改面板仅访问包装器同步方法 - 尝试将面板集合从 arralist 切换到矢量 - 尝试通过集合获取面板.synchronizedList() 这些都不起作用。此外,即使考虑到线程问题,它似乎也没有任何意义,因为我从完全相同的点调用方法,并且都执行相同的代码。
  • 另外,发生了一些奇怪的事情:我试图将neutralMode() 委托给queryPatternMode(),所以我在neutralMode() 上打印面板大小,然后调用queryPatternMode() 并再次打印面板大小.并且集合大小仍然不同!第一个零,然后是 20!方法范围是唯一定义集合可见大小的东西!
  • 有一点是肯定的——你所说的这些方法不会有任何区别,所以你可以完全排除这种情况。忘记这一点,继续思考替代方案。再次关注“面板”发生变化的地方。您是否可以在此处共享完整文件,或者至少以任何方式更改收集面板的方法?干杯
猜你喜欢
  • 2011-02-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-20
  • 1970-01-01
  • 2014-08-20
  • 1970-01-01
相关资源
最近更新 更多