Java 使用同步方法禁用事件侦听器

Java 使用同步方法禁用事件侦听器,java,swing,Java,Swing,我的GUI应用程序具有[重新]加载JTable实例数据的方法(例如File->New,File->Open菜单项)。加载或清空项时,事件侦听器处于活动状态,并开始处理处于未定义状态的对象,因此引发异常并与加载操作冲突 我想在加载操作期间停止侦听器。因此,我认为一种解决方案是使加载和侦听器方法同步 我拥有的是一些JTable的实例,侦听器是一个TableModelListener。因此,例如,当单击File->New时,它会触发以下方法: private synchronized void new

我的GUI应用程序具有[重新]加载
JTable
实例数据的方法(例如
File->New
File->Open
菜单项)。加载或清空项时,事件侦听器处于活动状态,并开始处理处于未定义状态的对象,因此引发异常并与加载操作冲突

我想在加载操作期间停止侦听器。因此,我认为一种解决方案是使加载和侦听器方法同步

我拥有的是一些
JTable
的实例,侦听器是一个
TableModelListener
。因此,例如,当单击
File->New
时,它会触发以下方法:

private synchronized void newFileClicked() { 
    // empty all tables in the application
}
在冲突的侦听器中:

class MyModelListener implements TableModelListener {
    @Override public void tableChanged(TableModelEvent tme) {
        synchronized (this) {
            // do stuff
        }
    }
}
但是,当调用
newFileClicked
方法时,该方法和
tableChanged
方法同时输出

我对
synchronized
的理解是否错误?或者这个实现是不正确的

两者都可以吗=/


编辑:回答后更正的执行也有相同的症状

Object lock = new Object();

private void newFileClicked() { 
    synchronized (lock) {
        // empty all tables in the application
    }
}

class MyModelListener implements TableModelListener {
    @Override public void tableChanged(TableModelEvent tme) {
        synchronized (lock) {
            // do stuff
        }
    }
}
// Still does not work ! =/

您似乎在不同的对象上使用了
synchronized
synchronized
仅当锁定在完全相同的对象上时才会被阻止

事实上,Swing是超级线程。将使用限制在AWT事件调度线程(EDT)-使用
java.AWT.EventQueue.invokeLater
。如果你需要其他的线,确保它们不会碰到任何东西。将数据复制到EDT上的EDT和从EDT复制数据。

系统级事件(如MouseEvents或KeyEvents)添加到事件调度线程(EDT)的末尾,并按顺序处理

Swing级别的事件(如TableModelEvent)在生成事件时进行处理。即事件未添加到EDT

我想在加载操作期间停止侦听器

您需要执行以下操作:

  • 删除侦听器
  • 加载数据
  • 恢复听众

  • 或者,您可以使用一个布尔变量,如“loading”,然后让每个侦听器检查您当前是否正在“loading”,如果是,则跳过处理。

    我的代码中关于此错误的观点很好。为了进行更正,我在主类中添加了一个字段,
    final private Object lock=new Object()
    ,并将其传递到内部类中的
    synchronized(lock){}
    块中。还在
    newFileClicked
    方法中添加了
    synchronized(lock){}
    块。然而,在纠正这一点之后,同样的“不同步”行为仍然会发生=/谢谢,我知道这些不同的方法。我更关心的是理解为什么
    synchronized
    不起作用。基本上你是说
    同步的
    方法和块在Swing中不起作用?为了确保与侦听器或线程同步,必须使用另一种方法,如布尔标志?我要说的是,没有任何东西可以同步,因为所有代码都在EDT上执行,所以它已经是单线程的了。当代码在多个线程上执行时,将使用同步。如果TableModelEvent是一个真正的系统事件,那么它将被添加到EDT的末尾,以便在清除表中的所有数据后执行,但它不是一个真正的事件,并且一旦从TableModel中清除数据,就会调用侦听器代码。