Question

I have a general question about something I've been working on and searching for answers on for 3 days now (and have basically given up on out of sheer frustration.)

Scenario 1;

A) method is called that creates and displays a "Please wait.." JWindow component with .setVisible(true)

B) method is called that does simple calculations and System.out's the results

C) "Please wait.." persists as expected during step B execution

D) step B terminates and .setVisible(false) is called on "Please wait" window and it goes way as expected

So far, so good.

Scenario 2;

Same as scenario 1 except that the work in step B is much more complex and calls a custom class which does a bunch of db queries/writes that take, on average, about 3-6 seconds to complete. The custom class is not runnable or threaded and is simply called with;

customClass cc = new customClass();
cc.makeMyDataPlease();
  • for whatever reason, in scenario 2, the .setVisible(true) step 'A' does not happen until after the complex work step 'B' is completed.

I've now spent 2 1/2 solid days experimenting with many of the solutions to these types of issues as found on this site and others with no luck. Tried swingworker, invokelater, thread, etc. and have concluded that I need to investigate this more before tearing out any more hair.

I had a similar issue with a method that connects to a URL and posts data. I was trying to just set the text on a simple JLabel just before the web connect routine started and it failed as well. The text was set after the web routine completed.

It's as though the VM was threading every statement execution.

My suspicion is that the mysql classes and the network URL classes share properties ( networking? ) that freeze out the other tasks that may not have had time to complete.

Here's my questions/confusions:

If the execution in a main java thread is sequential unless a new thread is created/called, why would anything interfere with that setVisible(true) statement? It logically must complete before the database routine statements are executed, and yet it does not.

What is the definitive way in java to ensure that one statement is fully executed before the next one? (Or at least, while the next one begins as I'm sure the VM can do a setVisible quickly enough that they could even start synchronously).

Thanks in advance

Specifically my question is; what are best practices when dealing with the concurrency issues involved with 'blocker' routines in java and how best to work within those confines.

Was it helpful?

Solution

Same as scenario 1 except that the work in step B is much more complex and calls a custom class which does a bunch of db queries/writes that take, on average, about 3-6 seconds to complete. The custom class is not runnable or threaded and is simply called with;

customClass cc = new customClass(); cc.makeMyDataPlease(); for whatever reason, in scenario 2, the .setVisible(true) step 'A' does not happen until after the complex work step 'B' is completed.

The problem is, Swing is a single threaded environment. All interactions with the UI are expected to be executed within the context of the Event Dispatching Thread. Any process which blocks this thread, will prevent it from processing new events, including paint requests.

What's happening is that scenario 2 is most likely blocking the EDT, preventing it from displaying the window, but instead, by the time all you processing has completed, the EDT is responding to the close event immediately after the open event.

Because of the way the framework is structured, you must ensure that;

  1. All interactions and modifications to the UI are done within the EDT
  2. Any long running or block process is done outside of the EDT.

Start by taking a look at Concurrency in Swing for more details.

Without further evidence, my gut feeling is to use a SwingWorker

For example...

import java.awt.EventQueue;
import java.util.concurrent.ExecutionException;
import javax.swing.JLabel;
import javax.swing.JWindow;
import javax.swing.SwingWorker;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class QuickWorker {

    public static void main(String[] args) {
        new QuickWorker();
    }

    public QuickWorker() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                JWindow window = new JWindow();
                window.add(new JLabel("Look no hands!"));
                window.pack();
                window.setLocationRelativeTo(null);

            }
        });
    }

    public class Worker extends SwingWorker<Object, Object> {

        private JWindow window;

        public Worker(JWindow window) {
            this.window = window;
        }

        @Override
        protected Object doInBackground() throws Exception {
            // Long running process...
            Thread.sleep(5000);
            return "All done";
        }

        @Override
        protected void done() {
            try {
                // Get the results of the process if you want them...
                get();
            } catch (InterruptedException | ExecutionException ex) {
                ex.printStackTrace();
            }
            window.dispose();
            // This is only here because the example will keep running without it :P
            System.exit(0);
        }
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top