Multithreading issue using System.out.print vs println

I have the following stream, which simply prints a dot every 200 ms:

public class Progress { private static boolean threadCanRun = true; private static Thread progressThread = new Thread(new Runnable() { public void run() { while (threadCanRun) { System.out.print('.'); System.out.flush(); try { progressThread.sleep(200); } catch (InterruptedException ex) {} } } }); public static void stop() { threadCanRun = false; progressThread.interrupt(); } public static void start() { if (!progressThread.isAlive()) { progressThread.start(); } else { threadCanRun = true; } } } 

I start a thread with this code (for now):

  System.out.println("Working."); Progress.start(); try { Thread.sleep(10000); //To be replaced with code that does work. } catch (InterruptedException ex) {} Progress.stop(); 

Which is really strange:

If I use System.out.println('.'); , the code works exactly as expected. (Besides the fact that I do not want a new line every time).

With System.out.print('.'); the code waits ten seconds and then displays the output.

System.out.println :

  Print dot, wait 200ms, print dot, wait 200ms etc... 

System.out.print :

  Wait 5000ms, Print all dots 

What happens and what can I do to get around this behavior?

EDIT:

I also tried this:

 private static synchronized void printDot() { System.err.print('.'); } 

and printDot () instead of System.out.print('.'); This still does not work.

EDIT2:

Interesting. This code works as expected:

  System.out.print('.'); System.out.flush(); //Makes no difference with or without System.out.println(); 

It does not mean:

  System.err.print('.'); System.err.flush(); System.out.print('.'); System.out.flush(); 

Solution: The problem is with netbeans. It worked fine when I run it as a jar file from java -jar.

This is one of the most unpleasant mistakes I've seen in my life. When I try to run this code using breakpoints in debug mode, everything works correctly.

+6
source share
6 answers

The string is buffered. Use stderr or clear PrintStream after each print. A.

+5
source

(This is weird code - there are much cleaner ways to write and manage threads. But this is not a problem.)

Your IDE should buffer line by line. Try to run it directly on the command line. (And I hope that the shell is also not buffered, but should not.)

+4
source

The println method automatically deletes the output buffer, but the print method does not. If you want to see the result right away, calling System.out.flush can help.

+1
source

I think this is because the println () method is synchronized

+1
source

(This is not an answer, but the questioner, David, asked me to move on to the minor issue of rewriting streaming. I can only publish the code this way.)

 public class Progress { private ProgressRunnable progressRunnable = new ProgressRunnable(); public void start() { new Thread(progressRunnable).start(); } public void stop() { progressRunnable.stop(); } private class ProgressRunnable implements Runnable { private final AtomicBoolean running = new AtomicBoolean(true); @Override public void run() { while (running.get()) { System.out.print('.'); System.out.flush(); try { Thread.sleep(200); } catch (InterruptedException e) { } } } private void stop() { running.set(false); } } public static void main(String[] args) { Progress progress = new Progress(); progress.start(); try { Thread.sleep(10000); } catch (InterruptedException e) { } progress.stop(); } } 
+1
source

I checked your code, System.out.print() and System.out.flush() . The code works for me, except for the code:

 while (!threadCanRun) { Thread.yield(); } 

in the class Progress. At the same time, the thread pauses the execution of another thread, as you can see in the api page thread. Removing this part, the code works.

But I don’t understand why you need yield method. If you call Progress.stop() , it will call the yield method. After the thread stops with interrupt (after waiting a huge amount of time on my computer). If you want to allow other threads to execute and pause the current thread, consider the join() method.

If you want to stop the current thread, perhaps you can consider removing while(!threadCanRun) or put Thread.currentThread().join() before Thread.interrupt() in the stop() method to wait for other threads to finish or just call p.stop() method.

Take a look at these posts .

0
source

Source: https://habr.com/ru/post/898064/


All Articles