Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsWhite Papers
Discussion GroupsFirst AidDatabasesJavaBeansGUIJava 3DVirtual MachineCORBASecurityToolsGeneral
Java DirectoryOpen Source ProjectsSample Book ChaptersUser GroupsWeb Resources
Related Topics
Databases.NETMore Topics ...

Java Forum / First Aid / September 2005

Tip: Looking for answers? Try searching our database.

How do you _really_ get a PrintStream to flush all the time?

Thread view: 
Rob McDonald - 29 Sep 2005 15:04 GMT
I create my own PrintStream directed to a JTextArea to act as a console for
a Swing application.  I found an example of doing this online & implemented
away...

Unfortunately, writing to the console isn't at all deterministic.  Messages
get trimmed.  They are printed out of order, linefeeds don't happen.
Generally, it is a mess.  And no end of flush() does any good at all...

Any suggestions are appreciated,

        Rob

public class Console extends JPanel {
static PrintStream out;
private PipedInputStream piOut;
private PipedOutputStream poOut;
private JTextArea textArea = new JTextArea();

public Console() throws IOException {
 piOut = new PipedInputStream();
 poOut = new PipedOutputStream(piOut);
 out = new PrintStream(poOut, true);
 textArea.setEditable(false);
 textArea.setRows(10);
 textArea.setColumns(80);
 add(new JScrollPane(textArea), BorderLayout.CENTER);
 setVisible(true);
 new ReaderThread(piOut).start();
}

class ReaderThread extends Thread {
 PipedInputStream pi;
 ReaderThread(PipedInputStream pi) {
  this.pi = pi;
 }
 public void run() {
  final byte[] buf = new byte[1024];
  try {
   while (true) {
   final int len = pi.read(buf);
   if (len == -1) {
    break;
   }
   SwingUtilities.invokeLater(new Runnable() {
   public void run() {
    textArea.append(new String(buf, 0, len));
    // Make sure the last line is always visible
    textArea.setCaretPosition(textArea.getDocument().getLength());
    // Keep the text area down to a certain character size
    int idealSize = 10000;
    int maxExcess = 5000;
    int excess = textArea.getDocument().getLength() - idealSize;
    if (excess >= maxExcess) {
     textArea.replaceRange("", 0, excess);
    }
   }
  });
 }
 } catch (IOException e) {
 }
 }
}
}
Rob McDonald - 29 Sep 2005 15:54 GMT
Ok, I just figured out a piece of the problem.  The console is created with
a reader thread.  Additionally, each time something comes into the buffer, a
new thread is created to append it to the JTextArea.  Races between these
threads are causing the problem.

If I remark out the subthread creation:
  SwingUtilities.invokeLater(new Runnable() {
  public void run() {
and the appropriate corresponding closing brackets, behavior improves
greatly.

However, then I run the danger of overrunning the buffer (and maybe other
problems).

I suspect that some clever use of synchronize is the proper cure for my
problem.  I'm not sure whether to synchronize on the JTextArea or on the
PrintStream, or what....

Thanks,

        Rob

> I create my own PrintStream directed to a JTextArea to act as a console for
> a Swing application.  I found an example of doing this online & implemented
[quoted text clipped - 59 lines]
>  }
> }
Roedy Green - 29 Sep 2005 17:14 GMT
>Unfortunately, writing to the console isn't at all deterministic.  Messages
>get trimmed.  They are printed out of order, linefeeds don't happen.
>Generally, it is a mess.  And no end of flush() does any good at all...

See http://mindprod.com/applets/fileio.html

Pour out your sorrows to it, and it will show you how to use
autoflush.
Signature

Canadian Mind Products, Roedy Green.
http://mindprod.com Again taking new Java programming contracts.

Rob McDonald - 29 Sep 2005 17:32 GMT
> >Unfortunately, writing to the console isn't at all deterministic.  Messages
> >get trimmed.  They are printed out of order, linefeeds don't happen.
[quoted text clipped - 4 lines]
> Pour out your sorrows to it, and it will show you how to use
> autoflush.

Sounds a bit like the Oracle.  I'll give it a shot.

       Rob
Rob McDonald - 29 Sep 2005 20:05 GMT
> > See http://mindprod.com/applets/fileio.html
> >
> > Pour out your sorrows to it, and it will show you how to use
> > autoflush.
>
> Sounds a bit like the Oracle.  I'll give it a shot.

Maybe I didn't pour enough of my sorrows into it (I have lots of them, it
could take a while), but I honestly don't have the slightest idea how this
is supposed to help me.

      Rob
Oliver Wong - 29 Sep 2005 22:08 GMT
> Maybe I didn't pour enough of my sorrows into it (I have lots of them, it
> could take a while), but I honestly don't have the slightest idea how this
> is supposed to help me.

   You're not alone; based on your description of the problem, it would
seem to me that the source of all this confusion is your use of threads, and
has nothing to do with FileIO.

   The situation you've got is a classic problem in multithreading known as
"producer/consumer". You should have a buffer of text (which is NOT the
JTextArea). You've got a producer which will put text into the buffer. You
should have a consumer which eats text out of the buffer and spits it back
out into the JTextArea. You want the producer to not produce text so fast
that it fills up the buffer and starts overwriting itself.

   Try this tutorial:
http://java.sun.com/docs/books/tutorial/essential/threads/synchronization.html

   - Oliver
Roedy Green - 30 Sep 2005 06:59 GMT
>    You're not alone; based on your description of the problem, it would
>seem to me that the source of all this confusion is your use of threads, and
>has nothing to do with FileIO.

That may well be. I was answering his question on how he could get an
autoflush.
Signature

Canadian Mind Products, Roedy Green.
http://mindprod.com Again taking new Java programming contracts.

Rob McDonald - 30 Sep 2005 17:35 GMT
>     The situation you've got is a classic problem in multithreading known as
> "producer/consumer". You should have a buffer of text (which is NOT the
> JTextArea). You've got a producer which will put text into the buffer. You
> should have a consumer which eats text out of the buffer and spits it back
> out into the JTextArea. You want the producer to not produce text so fast
> that it fills up the buffer and starts overwriting itself.

As I mentioned, the original code was found on the web somewhere, and I must
admit to pasting it in without taking the time to try to understand it.

In the producer/consumer model, I don't understand why the original author
bothered with the second thread.  From my point of view, the producers are
the rest of your program.  They throw text at the stream.  The consumer
thread reads from the stream and places the text in the JTextArea.

The original implementation's internal thread set just seems to insert a
middleman, which increases the opportunities for race conditions and
whatnot.  (It probably could've been locked properly, but there was no
synchronization done by that thread).

So, taking the code (clearing out any extraneous junk) and getting rid of
the middleman gives this:

public class Console extends JPanel {
static PrintStream out;
private PipedInputStream piOut;
private PipedOutputStream poOut;
private JTextArea textArea = new JTextArea();

public Console() throws IOException {
 piOut = new PipedInputStream();
 poOut = new PipedOutputStream(piOut);
 out = new PrintStream(poOut, true);
 add(new JScrollPane(textArea), BorderLayout.CENTER);
 setVisible(true);
 new ReaderThread(piOut).start();
}

class ReaderThread extends Thread {
 PipedInputStream pi;
 ReaderThread(PipedInputStream pi) {
  this.pi = pi;
 }
 public void run() {
  final byte[] buf = new byte[1024];
  try {
   while (true) {
    final int len = pi.read(buf);
    if (len == -1)
     break;
    textArea.append(new String(buf, 0, len));
   }
  } catch (IOException e) {}
 }
}
}

Because PipedInputStream / PipedOutputStream provide a buffered stream, the
size of buf [1024] doesn't seem all that critical.

I realize that if multiple threads send data to the stream, the order they
get displayed is unpredictable.  However, PrintStream.println() is
synchronized, so various messages shouldn't overlap or clash directly.
Also, I think that if one thread sends lots of messages, it is theoretically
possible for them to get displayed out of order.

I'm more concerned with preventing messages from getting truncated, lost,
and corrupted.  I'll deal with the rest of the realities of multi-threaded
output.

Does anyone see a problem with the above code?  Does anyone see a reason to
have the middleman thread?

         Rob
Roedy Green - 30 Sep 2005 05:45 GMT
>Maybe I didn't pour enough of my sorrows into it (I have lots of them, it
>could take a while), but I honestly don't have the slightest idea how this
>is supposed to help me.

Fid you tell it you wanted to write encoded characters to a file, say
buffered, uncompressed. It would then have shown you the following
code:

// Write Locale-encoded chars ( usually 8 bit ) into a buffered
sequential file.
// WARNING! unsigned Applets may not write to the local hard disk.
// To copy/download files see
http://mindprod.com/products.html#FILETRANSFER.

// import java.io.*;

// O P E N
FileOutputStream fos = new FileOutputStream( "C:/temp/temp.out" );
OutputStreamWriter eosw = new OutputStreamWriter( fos,"UTF-8" );
// usually UTF-8 for Unicode 8-bit giving the full Unicode set, no
BOMs.
// Cp437 is IBM OEM.
// See "encoding" in the Java glossary for alternatives
// such as UTF-16BE for 16-bit, big-endian Unicode characters.
BufferedWriter bw = new BufferedWriter( eosw, 4096 /* buffsize */ );

PrintWriter prw = new PrintWriter( bw, false /* auto flush on println
*/ );
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

// W R I T E
prw.write( "platypus" );
prw.println( 149 );
prw.flush();

// C L O S E
prw.close();

Signature

Canadian Mind Products, Roedy Green.
http://mindprod.com Again taking new Java programming contracts.

Roedy Green - 30 Sep 2005 05:43 GMT
>Sounds a bit like the Oracle.  I'll give it a shot.

It is probably one of the ugliest programs ever written inside, but
basically what I did was encapsulate as best I could every possible
combination of source/destination, type of data, compressed/buffered
and then glued bits of code together with a bit of logic so that it
would produce a plausible snippet for any combination of i/o request.

There is so much asymmetry in the io classes!

But boy has it saved me a lot of typing.  Any non-nio task I can just
point people to the applet to cut and paste code that works to give
them a skeleton starting point.  I use it myself.  It saves time
because you don't have typos to clear out.

I have been thinking about writing a companion nio version.  I am
trying to think how such a mess could be better organised, perhaps
using the enum feature.
Signature

Canadian Mind Products, Roedy Green.
http://mindprod.com Again taking new Java programming contracts.



Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.