The invokeLater loop

Discussion in 'Java' started by Stefan Ram, May 10, 2013.

  1. Stefan Ram

    Stefan Ram Guest

    I invented what I call the »invokeLater loop«:

    class Object implements java.lang.Runnable
    { int i = 0;
    public void run()
    { java.lang.System.out.println( i++ );
    javax.swing.SwingUtilities.invokeLater( this ); }}

    public class Main
    { public static void main( final java.lang.String[] args )
    { javax.swing.SwingUtilities.invokeLater( new Object() ); }}

    What is it good for?

    Maybe it provides a way to loop while still allowing
    Swing events to be processed in parallel? (So you do not
    always have to spawn another thread besides the EDT.)

    One also might see it as a kind of recursion that will not
    overflow that stack. But since it does not atually nest
    incarnations, it is not really adopted for recursive programming.
     
    Stefan Ram, May 10, 2013
    #1
    1. Advertising

  2. Stefan Ram

    Daniel Pitts Guest

    On 5/10/13 11:54 AM, Stefan Ram wrote:
    > I invented what I call the »invokeLater loop«:
    >
    > class Object implements java.lang.Runnable
    > { int i = 0;
    > public void run()
    > { java.lang.System.out.println( i++ );
    > javax.swing.SwingUtilities.invokeLater( this ); }}
    >
    > public class Main
    > { public static void main( final java.lang.String[] args )
    > { javax.swing.SwingUtilities.invokeLater( new Object() ); }}
    >
    > What is it good for?
    >
    > Maybe it provides a way to loop while still allowing
    > Swing events to be processed in parallel? (So you do not
    > always have to spawn another thread besides the EDT.)
    >
    > One also might see it as a kind of recursion that will not
    > overflow that stack. But since it does not atually nest
    > incarnations, it is not really adopted for recursive programming.
    >


    A few comments:

    That's isn't really a new invention.

    It isn't recursive.

    It encourages coupling the application logic to the UI environment.

    It is a good way to eat up CPU cycles if you don't want to have your CPU
    go idle. Also known as a laptop warmer.

    It doesn't take advantage of concurrent processing capabilities of most
    modern systems, ultimately slowing down both your EDT and your
    application processing.

    It is more error prone and harder to tune than using a SwingWorker.

    Unrelated to the point you made Stefan, I feel I should make a note on
    Stefan Ram(TM) convention. When I see "new Object()", and it isn't
    referring to java.lang.Object, it takes me 10 times as long to
    understand what the code is doing. I literally stared at that for 3 or 4
    seconds before it clicked that you were using confusing class names and
    hoping your abstruse convention would "clarify" the confusion.
     
    Daniel Pitts, May 10, 2013
    #2
    1. Advertising

  3. Stefan Ram

    Stefan Ram Guest

    Daniel Pitts <> writes:
    >It is a good way to eat up CPU cycles if you don't want to have your CPU
    >go idle. Also known as a laptop warmer.


    Say, I am writing an implementation of the »Game Of Life«. I have an
    endless main loop whose contents updates to the next generation.

    I want to have a sequence like:

    - calculate next generation
    - update screen
    - calculate next generation
    - update screeen
    - calculate next generation
    - ...

    I think that I can do this by calculating the next generation and
    updating the screen in »paintComponent« and then »invokingLater«
    paintComponent or requesting a screen update which indirectly will
    call »paintComponent« again. This will give the sequence above.

    Another possibility might be to calculate the next generation in
    a separate thread (SwingWorker). But I am not sure how to get
    the above sequence (without waiting an arbitrary period of
    times or complicated handshaking across thread boundaries).
     
    Stefan Ram, May 10, 2013
    #3
  4. Stefan Ram

    Daniel Pitts Guest

    On 5/10/13 12:40 PM, Stefan Ram wrote:
    > Daniel Pitts <> writes:
    >> It is a good way to eat up CPU cycles if you don't want to have your CPU
    >> go idle. Also known as a laptop warmer.

    >
    > Say, I am writing an implementation of the »Game Of Life«. I have an
    > endless main loop whose contents updates to the next generation.
    >
    > I want to have a sequence like:
    >
    > - calculate next generation
    > - update screen
    > - calculate next generation
    > - update screeen
    > - calculate next generation
    > - ...
    >
    > I think that I can do this by calculating the next generation and
    > updating the screen in »paintComponent« and then »invokingLater«
    > paintComponent or requesting a screen update which indirectly will
    > call »paintComponent« again. This will give the sequence above.

    Depending on the type of simulation, you might not actually want to wait
    for the screen to update before continuing. This is actually
    particularly true in multi-player games. GoL may be an exception of
    course, since typically users do want to see every frame.

    By the way, calling "repaint()" doesn't mean the screen is updated.
    You'd have to be actively updating the screen each loop.

    > Another possibility might be to calculate the next generation in
    > a separate thread (SwingWorker). But I am not sure how to get
    > the above sequence (without waiting an arbitrary period of
    > times or complicated handshaking across thread boundaries).
    >

    Calling SwingWorker.invokeAndWait() isn't that complicated of a boundary
    IMO.

    public class GoLMain {
    public static void main(String...args) {
    GameOfLifeSimulation gols = new GameOfLifeSimulation();
    GolUI ui = initUi();
    while (true) {
    Generation g = gols.nextGeneration();
    SwingUtilities.invokeAndWait(ui.generationPainterFor(g));
    }
    }
    }
     
    Daniel Pitts, May 10, 2013
    #4
  5. Stefan Ram

    Joerg Meier Guest

    On Fri, 10 May 2013 12:18:15 -0700, Daniel Pitts wrote:

    > Unrelated to the point you made Stefan, I feel I should make a note on
    > Stefan Ram(TM) convention. When I see "new Object()", and it isn't
    > referring to java.lang.Object, it takes me 10 times as long to
    > understand what the code is doing. I literally stared at that for 3 or 4
    > seconds before it clicked that you were using confusing class names and
    > hoping your abstruse convention would "clarify" the confusion.


    By this point, that must be intentional obfuscation, outright designed and
    intended to cause bugs and present a maintenance nightmare, and you won't
    convince me otherwise. Overwriting "Object" is so purely malicious that
    there is no way that it's just random ineptitude, especially not from
    Stefan, who certainly isn't clueless enough to not be aware of that.

    My best guess would be that it's a straw man in the hopes of someone
    complaining about a bug it caused, which could then be responded to with
    something along the lines of "If only you would fully qualify every class
    reference like me, this wouldn't have happened to you, this proves that
    imports are evil".

    But since Stefan generally does not address criticism of his coding style,
    we will most likely forever be left to wonder what particular insanity
    sparks the Stefan Ram(TM) convention ;)

    Liebe Gruesse,
    Joerg

    --
    Ich lese meine Emails nicht, replies to Email bleiben also leider
    ungelesen.
     
    Joerg Meier, May 10, 2013
    #5
  6. Stefan Ram

    Eric Sosman Guest

    On 5/10/2013 3:40 PM, Stefan Ram wrote:
    > Daniel Pitts <> writes:
    >> It is a good way to eat up CPU cycles if you don't want to have your CPU
    >> go idle. Also known as a laptop warmer.

    >
    > Say, I am writing an implementation of the »Game Of Life«. I have an
    > endless main loop whose contents updates to the next generation.
    >
    > I want to have a sequence like:
    >
    > - calculate next generation
    > - update screen
    > - calculate next generation
    > - update screeen
    > - calculate next generation
    > - ...
    >
    > I think that I can do this by calculating the next generation and
    > updating the screen in »paintComponent« and then »invokingLater«
    > paintComponent or requesting a screen update which indirectly will
    > call »paintComponent« again. This will give the sequence above.


    How long does "calculate the next generation" take?

    - If it takes "significant" time, you're tying up the EDT
    and making the GUI unresponsive during the calculation.

    - If it takes "insignificant" time, you might as well just
    go ahead and do the deed without all the fuss and bother.

    Either way, I see no use case for the scheme. (Also, I don't
    think you can rely on having one paintComponent() call per update:
    If your GUI gets minimized everything might just freeze, or if
    another window obscures part of your GUI you might get multiple
    paintComponent() calls to refresh the display, or multiple calls
    with different clip regions to paint around the intruder. You
    need some extra work to make sure paintComponent() only calls
    invokeLater() "when appropriate.")

    > Another possibility might be to calculate the next generation in
    > a separate thread (SwingWorker). But I am not sure how to get
    > the above sequence (without waiting an arbitrary period of
    > times or complicated handshaking across thread boundaries).


    Leapfrogging a Runnable from EDT moment to EDT moment with
    multiple invokeLater() self-invocations ... What a splendid way
    to avoid complication!

    It'd be simple enough to do it with a SwingWorker, if you
    wanted to. The GUI would create a SwingWorker instance to compute
    one generation and call execute() to start it, running its
    doInBackground() method on a worker thread. When doInBackground()
    finishes, the SwingWorker's done() method runs on the EDT, where
    it can paint the display, and create and launch another SwingWorker
    for the next generation. Easy-peasy.

    Personally, I'd do it by driving things from the calculation
    thread: Compute a new generation, compute the changes, send the
    changes to the EDT via invokeLater() while the calculation thread
    starts work on the next generation. Easy to control the frames-
    per-second rate, too, which I think would be horribly difficult
    using EDT-multiplexing.

    Perhaps there's an application for the leapfrog technique, but
    I've not yet heard or thought of one.

    --
    Eric Sosman
    d
     
    Eric Sosman, May 10, 2013
    #6
  7. On 10/05/2013 21:40, Stefan Ram allegedly wrote:
    > Daniel Pitts <> writes:
    >> It is a good way to eat up CPU cycles if you don't want to have your CPU
    >> go idle. Also known as a laptop warmer.

    >
    > Say, I am writing an implementation of the »Game Of Life«. I have an
    > endless main loop whose contents updates to the next generation.
    >
    > I want to have a sequence like:
    >
    > - calculate next generation
    > - update screen
    > - calculate next generation
    > - update screeen
    > - calculate next generation
    > - ...
    >
    > I think that I can do this by calculating the next generation and
    > updating the screen in »paintComponent« and then »invokingLater«
    > paintComponent or requesting a screen update which indirectly will
    > call »paintComponent« again. This will give the sequence above.


    Not sure I get this. If you are performing non-UI-related computations
    in your "Object" (I second Daniel's remarks on your choice of
    nomenclature, btw), then these will happen on the EDT. But they should
    actually be happening /off/ the EDT.

    So it seems to me either you are busying the EDT and lagging the app, or
    it's really just a laptop warmer. Perhaps another example would be useful.

    --
    DF.
     
    Daniele Futtorovic, May 10, 2013
    #7
  8. Stefan Ram

    markspace Guest

    On 5/10/2013 11:54 AM, Stefan Ram wrote:
    >
    > Maybe it provides a way to loop while still allowing
    > Swing events to be processed in parallel? (So you do not
    > always have to spawn another thread besides the EDT.)


    Swing events can't be processed in parallel, they're run on a single thread.
     
    markspace, May 10, 2013
    #8
  9. Stefan Ram

    Silvio Guest

    On 05/10/2013 08:54 PM, Stefan Ram wrote:
    > I invented what I call the »invokeLater loop«:
    >
    > class Object implements java.lang.Runnable
    > { int i = 0;
    > public void run()
    > { java.lang.System.out.println( i++ );
    > javax.swing.SwingUtilities.invokeLater( this ); }}
    >
    > public class Main
    > { public static void main( final java.lang.String[] args )
    > { javax.swing.SwingUtilities.invokeLater( new Object() ); }}
    >
    > What is it good for?
    >
    > Maybe it provides a way to loop while still allowing
    > Swing events to be processed in parallel? (So you do not
    > always have to spawn another thread besides the EDT.)
    >
    > One also might see it as a kind of recursion that will not
    > overflow that stack. But since it does not atually nest
    > incarnations, it is not really adopted for recursive programming.
    >


    What is with this horrible code layout. Really makes makes me not want
    to read the code.
     
    Silvio, May 10, 2013
    #9
  10. Stefan Ram

    Daniel Pitts Guest

    On 5/10/13 3:26 PM, Silvio wrote:
    > [snip]
    > What is with this horrible code layout. Really makes makes me not want
    > to read the code.


    Don't bother, Stefan is a long time poster refusing to cater to this
    audience.

    It is better than some, however. Not quite "troll level". Try reading
    some of qwertymonkey's code for instance.
     
    Daniel Pitts, May 10, 2013
    #10
  11. Stefan Ram

    Roedy Green Guest

    On 10 May 2013 18:54:38 GMT, -berlin.de (Stefan Ram)
    wrote, quoted or indirectly quoted someone who said :

    > Maybe it provides a way to loop while still allowing
    > Swing events to be processed in parallel? (So you do not
    > always have to spawn another thread besides the EDT.)


    You want Swing manipulation to run on the EDT and non Swing stuff to
    run on some other threads. invokeLater lets you put stuff on the
    Swing thread from some non-Swing thread. If you are already on the
    Swing thread, you don't need it.
    --
    Roedy Green Canadian Mind Products http://mindprod.com
    Nothing is so good as it seems beforehand.
    ~ George Eliot (born: 1819-11-22 died: 1880-12-22 at age: 61) (Mary Ann Evans)
     
    Roedy Green, May 11, 2013
    #11
  12. Stefan Ram

    Stefan Ram Guest

    I wrote on 2013-05-10:
    >I invented what I call the »invokeLater loop«:
    >class Object implements java.lang.Runnable
    >{ int i = 0;
    >public void run()
    >{ java.lang.System.out.println( i++ );
    >javax.swing.SwingUtilities.invokeLater( this ); }}
    >public class Main
    >{ public static void main( final java.lang.String[] args )
    >{ javax.swing.SwingUtilities.invokeLater( new Object() ); }}
    >What is it good for?


    I the meantime, I have actually used the invokeLater loop in
    an animation. From the functional requirements point of view,
    it did work. But it was by orders of magnitude slower than
    the same animation with a for loop. OTOH, the for loop blocks
    the EDT (if you do not want to start another thread, that is).
    So, I ended up using the for loop as an inner loop to do
    some iterations fast and then using invokeLater to call the
    next iterations of the for loop, so that the EDT gets some
    leeway to do other things. So I got my animation with a
    single thread of execution, running fast and the EDT still
    being responsive.
     
    Stefan Ram, Jan 31, 2014
    #12
  13. On 1/30/2014 18:44, Stefan Ram wrote:
    > I wrote on 2013-05-10:
    >> I invented what I call the »invokeLater loop«:
    >> class Object implements java.lang.Runnable
    >> { int i = 0;
    >> public void run()
    >> { java.lang.System.out.println( i++ );
    >> javax.swing.SwingUtilities.invokeLater( this ); }}
    >> public class Main
    >> { public static void main( final java.lang.String[] args )
    >> { javax.swing.SwingUtilities.invokeLater( new Object() ); }}
    >> What is it good for?

    >
    > I the meantime, I have actually used the invokeLater loop in
    > an animation. From the functional requirements point of view,
    > it did work. But it was by orders of magnitude slower than
    > the same animation with a for loop. OTOH, the for loop blocks
    > the EDT (if you do not want to start another thread, that is).
    > So, I ended up using the for loop as an inner loop to do
    > some iterations fast and then using invokeLater to call the
    > next iterations of the for loop, so that the EDT gets some
    > leeway to do other things. So I got my animation with a
    > single thread of execution, running fast and the EDT still
    > being responsive.
    >


    That doesn't make a lot of sense to me. Calling invokeLater schedules a
    task on the EDT. If you want something to run consistently, calling
    invokeAndWait would make more sense. But given modern computers have
    multiple processors with multiple cores, it really makes more sense to
    use a separate thread and do active rendering off the EDT or to use
    invokeAndWait and keep your rendering times short. Both will allow time
    for the EDT to process other things and give you fast and smooth animation.

    --

    Knute Johnson
     
    Knute Johnson, Jan 31, 2014
    #13
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Mohit Gupta

    InvokeLater

    Mohit Gupta, Jul 11, 2003, in forum: ASP .Net
    Replies:
    0
    Views:
    2,642
    Mohit Gupta
    Jul 11, 2003
  2. Ike
    Replies:
    2
    Views:
    892
    Harald Hein
    Oct 8, 2003
  3. ***C.Steamer***
    Replies:
    39
    Views:
    1,065
    Thomas G. Marshall
    Oct 29, 2004
  4. Richie
    Replies:
    13
    Views:
    1,940
    Richie
    Oct 29, 2005
  5. Isaac Won
    Replies:
    9
    Views:
    407
    Ulrich Eckhardt
    Mar 4, 2013
Loading...

Share This Page