4

Why would this code freeze my Swing Application? The Swing components are in a separate thread from my InfiniteLoop thread. If I introduce a sleep into the run() method before each print then the program works fine. Does any one have any clue?

public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            createAndShowGUI(); // <-- creates the swing frame and component
        }
    });

    Thread t = new Thread(new InfiniteLoop()); 
    t.start();
}

public class InfiniteLoop implements Runnable
{
    private static Logger logger = Logger.getLogger(InfiniteLoop.class);
    public void run()
    {
         while(true)
         {
              log.info("test");
         }
    }
}
David Gelhar
  • 27,873
  • 3
  • 67
  • 84
delita
  • 1,571
  • 1
  • 19
  • 25
  • For better help sooner, post an [SSCCE](http://sscce.org/). – Andrew Thompson Jun 01 '12 at 03:31
  • @AndrewThompson - Just curious - isn't that what he did? – Kevin Day Jun 01 '12 at 03:50
  • @KevinDay No. An SSCCE of a runtime problem should be a single source file able to be copied, pasted, compiled (with 0 changes), run & show the problem. As it is we have parts of two classes with no imports -> not an SSCCE. – Andrew Thompson Jun 01 '12 at 03:54
  • ok - fair enough. The example was sufficient for me to explain the behavior, but I agree that if I were going to actually try this out, it would have taken me an extra 30 or 40 seconds, and that may have been the difference between me taking the time or not. I'm just thrilled that the question was so well asked that it could be answered right away! Cheerio. – Kevin Day Jun 01 '12 at 04:06

1 Answers1

3

The answer here has to do with Java's thread scheduling implementation (or rather, the specifics of your platform's Java thread scheduling implementation). Most Java threading implementations wind up running a given thread (at a given priority level) until the thread enters a wait condition. Then the next thread in that priority level runs, etc... Note that the JVM spec does not specify the exact behavior - that's up to the JVM implementer to decide.

Instead of inserting sleeps into your worker thread, you may want to consider dropping the priority of the worker. Sleeping the thread will work, but it's a hassle to remember to do it, and it forces the worker thread to take longer to do things than it would otherwise have to. If you do wind up inserting sleep calls, do it for 0 milliseconds (that's enough to release the thread, but should return to executing immediately if there are no other threads active).

Here's an article that describes this a bit.

As a potential refinement: The invokeLater() call may wind up placing the runnable in a queue that never has a chance to dequeue because your background thread is taking all the CPU. An interesting experiment would be to move the startup of your background thread int the Runnable - this would give the EDT a chance to initialize before your background thread starts consuming the CPU.

public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            createAndShowGUI(); // <-- creates the swing frame and component

            Thread t = new Thread(new InfiniteLoop()); 
            t.start();
        }
    });

}

or even:

public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            Thread t = new Thread(new InfiniteLoop()); 
            t.start();

            createAndShowGUI(); // <-- creates the swing frame and component
        }
    });

}

I'd actually be interested in the results of this (not interested enough to actually test it, though :-) ). Some references I see online say that the EDT runs at a higher priority level by default (in which case, the EDT itself shouldn't be experiencing starvation). If you start the background thread from inside the EDT, does the Swing interface remain responsive?

Kevin Day
  • 16,067
  • 8
  • 44
  • 68
  • This answer is better than mine. 1+ to Kevin, and I will delete my weaker answer. – Hovercraft Full Of Eels Jun 01 '12 at 04:06
  • Bah - there are many ways to skin that cat. For what it's worth, I looked *hard* to find out what the default EDT thread priority is, and was unable to find a reference that stated it. I'd actually be a bit surprised if the EDT doesn't already run at a higher priority, but dropping the priority of the worker thread sure seems like the best first step. We may find that my answer (while technically accurate) makes squat worth of difference to the specifics of the question. – Kevin Day Jun 01 '12 at 04:08
  • very bad answer, really, never, don't start Thread from invokeLater ever, this is one way how to killing EDT, how do you know what's inside Thread, nor that Swing GUI potentialy waiting to Thread ended, aaaachh – mKorbel Jun 01 '12 at 05:29
  • in the case that GUI isn't already visible (EDT doesn't ended in the moment that GUi is visible) then first sleep() or wait() to block visibility of Swing Container – mKorbel Jun 01 '12 at 05:34
  • @mKorbel Starting a `Thread` from the EDT does not block the EDT. How else would you be able to start e.g. a `SwingWorker` from a certain user action ? In that case you also start a new `Thread` from the EDT, and that works just fine – Robin Jun 01 '12 at 06:31
  • @Robin SwingWorker is special API and is invoked from Future, this comment is my view, – mKorbel Jun 01 '12 at 06:34
  • @Robin btw I'm able to create a [bunch of variations based on this theme](http://stackoverflow.com/a/7944388/714968) – mKorbel Jun 01 '12 at 06:54
  • @KevinDay I just tried ur suggestion. This time the GUI did initialize properly. However, the inifinteloop thread still starving the AWT thread and this makes the GUI completely unresponsive again. – delita Jun 01 '12 at 12:15
  • @mKorbel - your opinion on starting threads from the EDT is interesting, but I think it's misinformed. You might want to actually take a look at the SwingWorker source code to see how it's implemented - there is nothing special about Future, etc... - that is just a convenience - under the covers, it's all done using threads. Remember that SwingWorker was only added to Java in the past couple of years - before that, those of us who wrote large GUI apps spun worker threads ourselves. – Kevin Day Jun 02 '12 at 13:44
  • @delita - so there's definitely still starvation going on, which makes me think that the EDT and your worker thread are running at the same priority. Try dropping the priority of your worker thread and see how it works then. – Kevin Day Jun 02 '12 at 13:45