Win a copy of Cross-Platform Desktop Applications: Using Node, Electron, and NW.js this week in the JavaScript forum!
  • Post Reply Bookmark Topic Watch Topic
  • New Topic

multi-threaded Swing  RSS feed

 
Mike Southgate
Ranch Hand
Posts: 183
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I'm not usre if this question belongs here or under the Swing forum, it covers both. I'm getting the following exception, multiple times, but not every time the line is encountered:

Exception occurred during event dispatching:
java.lang.NullPointerException
at devices.ForeRunner201XMLLoader$1.run(ForeRunner201XMLLoader.java:136)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:178)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:454)
at java.awt.EventDispatchThread.pumpOneEventForHierarchy(EventDispatchThread.java:201)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:151)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:141)
at java.awt.Dialog$1.run(Dialog.java:540)
at java.awt.Dialog.show(Dialog.java:561)
at java.awt.Component.show(Component.java:1133)
at java.awt.Component.setVisible(Component.java:1088)
at root.Rl$2.actionPerformed(Rl.java:192)
at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1786)
at javax.swing.AbstractButton$ForwardActionEvents.actionPerformed(AbstractButton.java:1839)
at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:420)
at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:258)
at javax.swing.AbstractButton.doClick(AbstractButton.java:289)
at javax.swing.plaf.basic.BasicMenuItemUI.doClick(BasicMenuItemUI.java:1113)
at javax.swing.plaf.basic.BasicMenuItemUI$MouseInputHandler.mouseReleased(BasicMenuItemUI.java:943)
at java.awt.Component.processMouseEvent(Component.java:5100)
at java.awt.Component.processEvent(Component.java:4897)
at java.awt.Container.processEvent(Container.java:1569)
at java.awt.Component.dispatchEventImpl(Component.java:3615)
at java.awt.Container.dispatchEventImpl(Container.java:1627)
at java.awt.Component.dispatchEvent(Component.java:3477)
at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:3483)
at java.awt.LightweightDispatcher.processMouseEvent(Container.java:3198)
at java.awt.LightweightDispatcher.dispatchEvent(Container.java:3128)
at java.awt.Container.dispatchEventImpl(Container.java:1613)
at java.awt.Window.dispatchEventImpl(Window.java:1606)
at java.awt.Component.dispatchEvent(Component.java:3477)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:456)
at java.awt.EventDispatchThread.pumpOneEventForHierarchy(EventDispatchThread.java:201)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:151)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:145)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:137)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:100)



I wrote a process to read an XML file and then update a mysql database from it. I tested it using the command line only and it worked fine. Now I'm putting a swing front end on it. Because the process takes a while I'm using a separate thread which I'm starting from the button's action listener like this:

//import the data on a separate thread
Thread importThread = new Thread() {
public void run() {
//do the xml parsing and database update here
ForeRunner201XMLLoader frLoader = new ForeRunner201XMLLoader(file, user, action, dialog);
frLoader.loadDB();
} //run method

}; //importThread class
importThread.start();

One of the methods in the ForeRunner201XMLLoader class updates a swing field
to let the user know how we're progressing like this:

if (runA != null) {
runA.saveInDb();
SwingUtilities.invokeLater(new Runnable() {
public void run() {
Integer I = new Integer(runA.getRunId());
String s1 = I.toString();
String runCnt = "Importing run # : " + s1;
//+ (new Integer(runA.getRunId())).toString();
parent.updateImportStatus(runCnt);
} //run method
}); //
runA = null;
} //if

The line that's giving me the error - intermittently - is:
Integer I = new Integer(runA.getRunId());
I only get the error about 10% of the time at most, and don't get it at all
in the non-threaded version. I can see the text on the screen changes as the
file is processed and the database is updated, so it's working other than the exceptions.

How should I go about debugging this?

ms
 
Ernest Friedman-Hill
author and iconoclast
Sheriff
Posts: 24217
38
Chrome Eclipse IDE Mac OS X
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Well, the code in the "invokeLater()" Runnable is (as the name of the method suggests) invoked later. There's a null guard around the call to invokeLater(), but not around the contents of the Runnable.run() method. SO what I'm thinking is that runA (whatever that is!) is non-null, and you set up the invokeLater() call, but before the Runnable runs, runA is set to null.

There are two ways you might deal with this (although with a strong caveat as expressed below.) They both have slightly different semantics -- only you know which would be correct.

First, you could put a null check inside the Runnable, so the runnable doesn't run if the member is null.

Second, you could copy the value of runA into a local final variable, inside the existing null check, and then refer to that variable instead of runA inside the Runnable; then the runnable always runs, even if the member variable is null.

The caveat: you still could get an occasional NPE due to race conditions -- i.e., after the null check, but before you use the variable, it could be set to null. To deal with this, and make sure you never get an NPE, you have to make sure all the accesses of runA are synchronized, such that once one thread has access to it, all the other threads must wait. You could do this regardless of which of the above options you choose.
 
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!