Raf
Raf

Reputation: 1757

Disable event listeners with synchronized methods

My GUI application has methods that [re-]load data for JTable instances (like eg File->New, File->Open menu items). When items are being loaded or emptied, the event listeners are active and start handling objects in an undefined state, hence raising exceptions and conflicting with the loading operation.

I want to stop the listeners during loading operations. So I thought one solution would be making both the loading and the listener methods synchronized.

What I have is a few instances of JTable, and the listener is a TableModelListener. So, for example, when File->New is clicked, it fires this method:

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

And in the conflicting listener:

class MyModelListener implements TableModelListener {
    @Override public void tableChanged(TableModelEvent tme) {
        synchronized (this) {
            // do stuff
        }
    }
}

But still, when the newFileClicked method is called, simultaneous output from this and the tableChanged methods occur.

Is my understanding of synchronized wrong? Or is this implementation not correct?

May be both ?=/


edit: corrected implementation after this answer also has the same symptom

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 ! =/

Upvotes: 0

Views: 213

Answers (2)

camickr
camickr

Reputation: 324157

System level events (like MouseEvents or KeyEvents) are added to the end of the Event Dispatch Thread (EDT) and are processed sequentially.

Swing level events (like the TableModelEvent) are processed at the time the event is generated. That is the event is NOT added to the EDT.

I want to stop the listeners during loading operations.

You need to do something like:

  1. remove the listeners
  2. load the data
  3. restore the listeners

Or you could use a a boolean variable like "loading" and then have each of the listeners check if you are currently "loading" and if so, skip the processing.

Upvotes: 1

Tom Hawtin - tackline
Tom Hawtin - tackline

Reputation: 147154

You appear to be using synchronized on different objects. synchronized will only block if a lock is held on exactly the same object.

In fact, Swing is super thread-hostile. Restrict usage to the AWT Event Dispatch Thread (EDT) - use java.awt.EventQueue.invokeLater. If you need other threads, make sure they don't touch anything Swing. Copy data to and from the EDT on the EDT.

Upvotes: 0

Related Questions