在命令行上更新线程进度

时间:2013-07-05 12:04:32

标签: java multithreading command-line progress-bar command-line-interface

我正在尝试使用线程在java中的CLI上显示进度条,同时执行长操作(为一批大文件生成md5sums)。

我已经编写了一些代码,但它确实有用,但我想知道我是否正确使用了线程,因为我对此很陌生。

我有两个类文件,ProgressThreadTest.javaCountToABillion.java

CountToABillion.java:

public class CountToABillion implements Runnable {

    double count = 0;

    public void echoCount() {
        System.out.println(count);
    }

    @Override
    public void run() {     
        for (double x=0;x<1000000000;x++) {
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            count = x;
            echoCount();
        }       
    }   
}

ProgressThreadTest.java:

public class ProgressThreadTest {

    public static void main(String[] args) throws InterruptedException {

        Thread doCount=new Thread(new CountToABillion());
        doCount.start();
    }   
}

它按预期工作,并在命令行上向上计数。

任何人都对这是否是一种做线程的好方法有任何意见?

另外,因为我正在更新计数循环中的进度,所以它将每10ms更新一次。如何将代码更改为每秒只输出一次计数?

4 个答案:

答案 0 :(得分:2)

使用javax.swing.Timer可能是更简单的解决方案:

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Timer;

public class CountToABillion implements Runnable {

    double count = 0;
    Timer progressTimer;

    public void echoCount() {
        System.out.println(count);
    }

    @Override
    public void run() {
        progressTimer = new Timer(1000, new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                echoCount();
            }
        });
        progressTimer.setRepeats(true);
        progressTimer.start();

        for (double x=0;x<1000000000;x++) {
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            count = x;
        }
        progressTimer.stop();
    }
}

使用java.util.concurrent.ScheduledThreadPoolExecutor是更好,更具伸缩性的解决方案:

import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class CountToABillion implements Runnable {

    double count = 0;
    ScheduledThreadPoolExecutor exec = new ScheduledThreadPoolExecutor(1);

    public void echoCount() {
        System.out.println(count);
    }

    @Override
    public void run() {
        Runnable task = new Runnable() {
            public void run() {
                echoCount();
            }
        };
        exec.scheduleAtFixedRate(task, 1, 1, TimeUnit.SECONDS);

        for (double x=0;x<1000000000;x++) {
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            count = x;
        }
        exec.shutdownNow();
    }
}

答案 1 :(得分:1)

@Override
public void run() {     
    for (int i = 0; i < 1000000000; i++) {
        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        count = i;

        if(i % 100 == 0) {
            echoCount();
        }
    }
}

使用i % 100 == 0您正在检查i是否可被100整除而没有静止值。如果是这种情况,则意味着您运行了100次10毫秒,即1000毫秒,即1秒。因此,您将每秒输出echoCountt()

这是一种使用线程的好方法。但是你的线程将继续运行,直到它已经计入10000000秒。

在旁注中,你应该在for循环中使用'i'而不是'x'。它的使用范围更广泛,对于经验丰富的Java开发人员来说更容易阅读

答案 2 :(得分:1)

选项1:

    int sleep = 10; //ms
    int echo = 1000; //ms
    for (double x=0;x<1000000000;x++) {
        try {
            Thread.sleep(sleep);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        count = x;
        if((x*sleep % echo) == 0) {
            echoCount();
        }
    }

选项2:

  • 创建一个新的类来管理你的计数器,它应该能够添加,重置等等。您必须确保它的线程安全(如果您想从各种线程更新,请编写新值)。
  • 制作一个在给定间隔内增加计数器的线程
  • 制作另一个线程,以其他给定的间隔轮询当前计数并打印。

答案 3 :(得分:1)

long last=0;
@Override
public void run() {     
    for (double x=0;x<1000000000;x++) {
        try {
            doWork();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        count = x;
        if((System.currentTimeMillis()-last)>=1000) //post every second
        {
            last=System.currentTimeMillis();
            echoCount();
        }
    }       
} 

如果“工作”不超过一秒,这将每秒打印一次计数。