Re: How do you _really_ get a PrintStream to flush all the time?
- From: "Rob McDonald" <robm@xxxxxxxxxxxxxxxxxxxxxx>
- Date: Fri, 30 Sep 2005 12:35:46 -0400
> 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
.
- References:
- How do you _really_ get a PrintStream to flush all the time?
- From: Rob McDonald
- Re: How do you _really_ get a PrintStream to flush all the time?
- From: Roedy Green
- Re: How do you _really_ get a PrintStream to flush all the time?
- From: Rob McDonald
- Re: How do you _really_ get a PrintStream to flush all the time?
- From: Rob McDonald
- Re: How do you _really_ get a PrintStream to flush all the time?
- From: Oliver Wong
- How do you _really_ get a PrintStream to flush all the time?
- Prev by Date: Re: How to use a DLL created using VB in Java?
- Next by Date: Re: How often does a Java Web Start application update itself?
- Previous by thread: Re: How do you _really_ get a PrintStream to flush all the time?
- Next by thread: Limiting the maximum number of threads created by Tomcat
- Index(es):