1

I'm displaying progress in the console, and using the '\r' character to clear the line between each update, as per this answer.

public class MainTest {
    public static int delay = 10;

    public static void main(String[] args) {
        for (int i = 0; i <= 100; i++) {
            System.out.print("\r");
            System.out.print("process:" + i + "%");
            Thread.sleep(delay);
        }
    }
}

With a delay of 240 ms or more, it seems to works fine. However, once I go below this, the '\r' character is not reliable. It looks jittery, and doesn't always clear the line, so at the end you see

process:97%process:98%process:99%process:100%

This gif shows the difference between update speeds. I don't want my program to run slower, just so that the console output looks nice. How can I fix this?

Community
  • 1
  • 1
doublez
  • 19
  • 2

1 Answers1

0

One option is to split your code into two threads, running in parallel. Your worker thread does all your work logic, and updates a 'progress' variable. Every now and then, your UI thread reads the progress, and displays it in the console.

import java.util.concurrent.atomic.AtomicInteger;

public class HelloWorld
{
    public static void main(String[] args) throws InterruptedException
    {
        final AtomicInteger progress = new AtomicInteger(0);

        Thread worker = new Thread(new Runnable() {
            public void run() {
                for (int i = 0; i <= 100; i++) {
                    try {
                        // Do some work here
                        Thread.sleep(1);
                        progress.set(i);
                    } catch (InterruptedException e) {
                        progress.set(100);
                    }
                }
            }
        });

        worker.start();

        while (progress.get() < 100) {
            // Now you can choose how often to update the console, without
            // slowing down your worker.
            Thread.sleep(240);
            System.out.print("\r");
            System.out.print("Progress: " + progress.get() + "%");
        }

        worker.join();
    }
}

It is very common for the UI code to be run on a separate thread to the application logic, mostly so that when something is taking a long time, it doesn't stop the user from interacting - they can still click close, switch between tabs, etc.

Andrew Williamson
  • 8,299
  • 3
  • 34
  • 62
  • “Thread.sleep(240);” ,if you go below 240 ,like 20ms,10ms in the IDE console you will find it is not reliable, but in the linux shell it works fine. I don't know what other people do,like '\b'. – doublez Apr 14 '17 at 13:01
  • Yeah, the point of this code is that you can choose any update frequency, without affecting how fast your worker runs. It is a rather arbitrary choice though - even if you chose a 1 second sleep, you might still have the same problem on slow computers. This is the best solution I can think of. – Andrew Williamson Apr 14 '17 at 20:29