Search code examples
javamultithreadingswingdebuggingswingworker

Background SwingWorker thread not executing a particular piece of code


I couldn't find a better way to express the problem in the title of the question, but hopefully you'll understand...

I have the following code...

[...]
final JDialog waitingDialog = optionPane.createDialog(optionPane, "Processing in backgroung");

waitingDialog.setLocationRelativeTo(homeFrame);
waitingDialog.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);


SwingWorker<Void, Void> backgroundThread = new SwingWorker<Void, Void>() {

    @Override
    protected Void doInBackground() throws Exception {
        // Background processing is done here
        System.out.println("[DEBUG] -- Background processing has started");
        MyCustomClass.initParameters();
        System.out.println("DEBUG] -- initParameters() has finished. Starting main processing now...");
        waitingDialog.setVisible(true);
        MyCustomClass.run();
        return null;
    }

    // This is called when background thread above has completed
    @Override
    protected void done() {
        waitingDialog.dispose();
    };
};
backgroundThread.execute();

[and does other things after this...]

... which executes just fine until it hits MyCustomClass.run(). When it is supposed to start such method, it simply doesn't do it. The application doesn't pause, stop or crash... it just keeps on waiting to continue after the background processing is done, which is not happening for some unknown reason.

MyCustomClass.run() is a static method over at MyCustomClass. I suspected the problem could be with its name - run - so I changed it to some random thing like "doIt()", but the issue persisted. The very first line on the method is a simple System.out.println("I got here"), but not even that gets printed. I added breakpoints just before and right after the method invocation and tried debugging, but that didn't help either. Everything seemed fine and I couldn't find out the problem.


Edit
I ask: how do I make the dialog show only when I wanted it to show? In other words, the script is:

  1. show the "waiting" dialog when SwingWorker is started
  2. hide/stop/disable/dispose the dialog when the initParameter() issues the option dialog that needs user input (press of a button);
  3. show the waiting dialog again as the processing resumed
  4. dispose of the dialog because the background processing has completed

Solution

  • Immediately off the bat I see that you're making Swing calls from within the SwingWorker's doInBackground, something which completely defeats the purpose of using a SwingWorker or background thread. Also, the call you're making, one that displays a modal dialog:

    waitingDialog.setVisible(true); // **** here ****
    MyCustomClass.run();   // **** not sure what this does or if this makes Swing calls or not.
    

    will pause all code flow below it until the dialog is no longer visible, as that is how modal dialogs function. This is what is blocking your SwingWorker. You must try to separate your code so that Swing calls are only made on the Swing event thread, and use the worker for only the background work.

    Instead

    • Create your SwingWorker
    • Execute your SwingWorker
    • Then call setVisible(true) on your modal dialog

    In pseudocode:

    create modal dialog
    create SwingWorker
    Attach any PropertyChangeListeners to the SwingWorker (if needed)
    Execute the SwingWorker
    Display the modal dialog
    

    So, the first quick change I would make in your code above would be to remove waitingDialog.setVisible(true); from your SwingWorker doInBackground() method, and then call the waitingDialog.setVisible(true); method AFTER executing the SwingWorker, i.e., after backgroundThread.execute(); in particular. I know it seems counter-intuitive to call dispose on it seemingly before making it visible, but trust me, it will work better this way, since the dispose call will be blocked by the time it takes to run the background thread.