This discussion is archived
9 Replies Latest reply: Mar 13, 2013 9:08 AM by 801327 RSS

SwingWorker newbie

870083 Newbie
Currently Being Moderated
So after trying to avoid creating additional threads in my software but I have finally had to write some software which requires it. I've refreshed my memory on the basics of threads, been reading through Java Concurrency in Practice by Bloch and co. and been going through the official tutorials.

I've found it very overwhelming with all the collections, concepts and ways to do things but finally decided to settle for the use of a swingworker to carry out a large number of calculations so that the EDT is freed up for the GUI and my progress bar. I was originally looking at the executor framework so I could break up my calculations and help speed things up but soon realised I had bitten off more than I could chew!

I seem to have got everything working fine but I just have 2 questions:
- All the calculations, objects created etc. are all contained within the swingWorker thread but is it thread safe for the thread to access the GUI (eg. add things to a table, disable a button etc.) even though it is being handled by the EDT?
- When exceptions are thrown inside the new thread (due to the calculations such as NullPointerException) everything comes to a hault and the exception seems to be hidden, I only realised what was going on when I run the calculations method directly without creating a thread. What is going on and what am I doing wrong?

Thanks.
  • 1. Re: SwingWorker newbie
    Kayaman Guru
    Currently Being Moderated
    Technical wrote:
    I seem to have got everything working fine but I just have 2 questions:
    - All the calculations, objects created etc. are all contained within the swingWorker thread but is it thread safe for the thread to access the GUI (eg. add things to a table, disable a button etc.) even though it is being handled by the EDT?
    No. You can't access the GUI from anywhere except the EDT (well, there are rare exceptions). You need to perform the modifications with invokeAndWait or invokeLater, like normally.
    - When exceptions are thrown inside the new thread (due to the calculations such as NullPointerException) everything comes to a hault and the exception seems to be hidden, I only realised what was going on when I run the calculations method directly without creating a thread. What is going on and what am I doing wrong?
    It's hard to say without knowing what your code does. Naturally if your thread just ups and dies (don't you catch exceptions in your thread?) and other threads are depending on it, you can see things breaking.
  • 2. Re: SwingWorker newbie
    870083 Newbie
    Currently Being Moderated
    Ah yes of course. I do that for the initial setup of the GUI. I'll give it ago.
    I was just thinking actually, I'm sure I read that the done method of SwingWorker is callled from the EDT so is it possible to make changes in there safely without using invokeLater?

    I haven't got the code to post right now but basically all within doInBackground method it creates some objects, carries out calculations and stores them within the objects but say one of my loops is wrong and it throughs a ArrayOutOFBoundsException then the program stops, there is no further output to the console and there is no way of knowing why. I run the calculations in the EDT and I get the exception printed to the console.

    If it's no more clear I will try to post some code.

    Thanks.
  • 3. Re: SwingWorker newbie
    abillconsl Explorer
    Currently Being Moderated
    Perhaps I'm not clear on what you are doing, but ... first off, you should make sure that your work in this separate thread is fool proof and can't fail catistrophically - that is, that every effort should be made to assure that all error conditions are accounted for and handled in a fail safe way - that the end user is never presented with ... well ... remember the old Windows blue screen? ... need I say more? After that, exactly how you're using the SwingWorker and doing your work and updating your GUI is still a bit fuzzy ... to me at least. You might want to clarify that.
  • 4. Re: SwingWorker newbie
    870083 Newbie
    Currently Being Moderated
    Here is a sample of what I am doing within a SwingWorker:
    @Override
        protected Void doInBackground() throws Exception {
            totalProgress = BigInteger.ZERO;
            this.addPropertyChangeListener(this);
            MainGUI.setCurrentActionLabel("Creating parameter set.");
            ps = MainGUI.createParameterSet();
            
            MainGUI.setCurrentActionLabel("Creating beams.");
            beamsPerPercent = calcBeamsPerPercent(ps);
            beams = BeamBuilder.buildBeams(ps, this, beamsPerPercent, false);
            Analyser.analyseBeams(beams, this);
            return null;
        }
        
        @Override
        public void done() {
            MainGUI.setCurrentActionLabel("Applying final adjustments.");
            MainGUI.setBeams(beams);
            MainGUI.setupResultsPanel(ps, beams);
            MainGUI.setCurrentActionLabel("Finished.");
            JOptionPane.showMessageDialog(null,
                    "Beams created and analysis complete.",
                    "Experiments Complete",
                    JOptionPane.INFORMATION_MESSAGE);
        }
    I know that ideally I don't want the the JRE to come across an exception such as an ArrayOutOfBounds but does that mean during development until I have fixed all the bugs I can't run this as a separate thread?

    Also I am confused as to how to manage interation with the GUI. I have always read that the EDT has to make the alterations and to do that you must use invokeLater etc. It seems like I would be doing this alot and I don't know how to get around local variables being outside the scope of the new runnable.

    Does that mean I have to pass a new runnable into the EDT for any interation with the GUI eg. getting a value from a table or setting what text is in a textbox?
    Even for a simple method such as this (changing a JLabel):
    public static void setCurrentActionLabel(String text){
            currentActionLabel.setText("Current Action: " + text);
    }
  • 5. Re: SwingWorker newbie
    abillconsl Explorer
    Currently Being Moderated
    I can understand your confusion. It isn't the easiest thing to get a good handle on. Have you read the tutorial on swing concurancy thought? Here it is:

    http://docs.oracle.com/javase/tutorial/uiswing/concurrency/index.html

    After reading through it, why not post back specific questions about what you've read? Also, have a read through the SwingWorker class in the Java API docs.
  • 6. Re: SwingWorker newbie
    jduprez Pro
    Currently Being Moderated
    I'm sure I read that the done method of SwingWorker is callled from the EDT so is it possible to make changes in there safely without using invokeLater?
    Yes.
    Not only that ( done() is indeed called in the EDT after the work in the worker thread has completed), but the method process(...) is also called in the EDT (to e.g. display intermediate results).

    That's explained somewhere in the Swing tutorial chapter about concurrency (see abillconsl's link above).

    >
    I haven't got the code to post right now but basically all within doInBackground method it creates some objects, carries out calculations and stores them within the objects but say one of my loops is wrong and it throughs a ArrayOutOFBoundsException then the program stops, there is no further output to the console and there is no way of knowing why. I run the calculations in the EDT and I get the exception printed to the console.
    As suggested, put a try-catch block at the top-level of your worker's doInBackground() method, to more nicely know and react when an Exception is thrown in the worker thread.
    Alternately, update some (volatile) flag at the very end of doInBackground() , and check the flag in done() to update display accordingly (if flag is not set, then the worker did not complete normally).

    Best regards

    J.
  • 7. Re: SwingWorker newbie
    839063 Newbie
    Currently Being Moderated
    I have found the SwingWorker's publish and process generally sufficient to accomplish what you are trying to do with your MainGui.setCurrentActionLabel calls. You can get creative on what V chunks are.
  • 8. Re: SwingWorker newbie
    870083 Newbie
    Currently Being Moderated
    Thanks for he great replies. I have been through the official tutorial which is good but I think I have read too much material and deciding which method is correct for your needs is difficult when you are a beginner coming from basic threads and only want to do something relatively simple.

    I managed to rework my code and make it thread safe, I think I'm starting to get my head around it now and it's pretty straight forward with this method. I added a try/catch block for the swingworker and now exceptions are appearing again once the done method is called. I'm suprised it didn't force me to catch the threads exceptions...

    I shall stick to this method for now and forget the rest.

    Thanks.
  • 9. Re: SwingWorker newbie
    801327 Newbie
    Currently Being Moderated
    You have pretty much got it figured out. I use SwingWorker a lot, and the things to know about it are:

    1) Do GUI updates in the process() and done() methods. Pass stuff to process() by calling publish() in the doInBackground() method.
    2) I recommend always wrapping your doInBackground() code in a try/catch for Exception. doInBackground() throws Exception, but if you let it, any exception will disappear into a black hole as you have found out. So always wrap the code in a try/catch and at least log the error somewhere if it happens.
    3) There is some oddness to SwingWorker behavior if cancel() is called on it. Beware that, depending on the Java version, process() can potentially be executed after done() if cancel is called. Based on what I've read, you may also need to be sure cancel() is called from the EDT. You may wish to research this more if you expect to make use of calling cancel() on your SwingWorker.
    4) In some versions of Java, multiple SwingWorkers can block each other (java bug 6880336). Only a problem if your application might have multiple SwingWorkers all running at the same time. If this is an issue for your application, you can avoid the problem by launching SwingWorkers in a cached thread pool.

Legend

  • Correct Answers - 10 points
  • Helpful Answers - 5 points