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



> 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


.