3 Replies Latest reply: Jan 30, 2013 11:46 AM by Nikolai Varankine RSS

    Why wait() is needed in between successive additions to TextArea?

    Nikolai Varankine
      Guys, please help to understand one point in implementation of text console using TextArea.

      The purpose of console is to show messages arriving from other threads and clean too old ones from the area, keeping reasonable buffer size.

      The problem is that when application threads send messages to console too fast, console hangs entire GUI. Application works, standard Java logging works, but menus, scrolbars, console text view, etc. become inresponsive. I see no exceptions reported. More interestingly, the application runs pretty fine when invoked under NetBeans. Running natively (java -jar app.jar), it hangs within first seconds after active reportings started.

      Making example, very close to my application, I discovered that when atomic sendings are separated by tiny LOCK.wait(0,1) or Thread.sleep(0,1), the problem disappears. Another problem is that invocations of wait() cannot be inserted in real code by means of application (many threads are submitting messages).

      So the questions are:
      1. Is design wrong in principle, in terms of JavaFX application?
      2. Why delay is needed?
      3. Is anybody experiencing same problem?
      4. Are there known solutions for the problem?

      The sample code follows. It structurally differs from what I'm developing (please don't point to), but serves well to reproduce original problem. Code runs on Intel Quad 2.6GHz, WindowsXP, javafx 2.1, java 7u4.
      package test;
      
      import java.util.*;
      import java.util.logging.*;
      import javafx.application.*;
      import javafx.scene.Scene;
      import javafx.scene.control.*;
      import javafx.stage.Stage;
      
      public class JavaFXTextAreaTest extends Application
      {
          public static void main( String[] args )
          {
              launch( args );
          }
          
          static final String SAMPLE = "0123456789\n";
          static final Object LOCK = new Object();
          
          TextArea console;
          
          @Override
          public void start( Stage primaryStage )
          {
              primaryStage.setTitle( "Hello TextArea!" );
              
              console.setManaged( true );
              console.setEditable( false );
              
              ScrollPane root = new ScrollPane(); // console is scrollable
              root.setContent( console );
              root.setFitToHeight( true );
              root.setFitToWidth( true );
              primaryStage.setScene( new Scene( root, 300, 250 ) );
              primaryStage.show();
          }
          
          @Override
          public void init() throws Exception
          {
              console = new TextArea();
              
              new Timer().schedule( new TimerTask()
              {
                  @Override
                  public void run()
                  {
                      int i = 0;
                      while( true )
                      {
                          // simulate sending a message
                          String msg = SAMPLE.replace( '0', Integer.toString( i ).charAt( 0 ) );
                          i = ++i % 10;
                          Platform.runLater( new Sender( console, msg ) );
      
                          // strange delay required. TRY TO COMMENT IT OUT TO GET APPLICATION HANGED
                          synchronized( LOCK )
                          {
                              try
                              {
                                  LOCK.wait( 0, 1 );
                              }
                              catch( InterruptedException ex )
                              {
                                  Logger.getLogger( JavaFXTextAreaTest.class.getName() ).log( Level.SEVERE, null, ex );
                              }
                          }
                      }
                  }
                  
              }, 5000 ); // delay messaging to get GUI ready
          }
          
          static class Sender implements Runnable
          {
              final TextArea console;
              final String text;
      
              Sender( TextArea console, String text )
              {
                  this.console = console;
                  this.text = text;
              }
      
              @Override
              public void run()
              {
                  // manage reasonable console buffer
                  int len = SAMPLE.length();
                  if( console.getText().length() > len*10 ) // limit of 10+1 lines shown
                      console.deleteText( 0, len);
      
                  // put new message on screen
                  console.appendText( text );
              }
              
              
          }
      }