我正在尝试使用线程在java中的CLI上显示进度条,同时执行长操作(为一批大文件生成md5sums)。
我已经编写了一些代码,但它确实有用,但我想知道我是否正确使用了线程,因为我对此很陌生。
我有两个类文件,ProgressThreadTest.java
和CountToABillion.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更新一次。如何将代码更改为每秒只输出一次计数?
答案 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();
}
}
}
如果“工作”不超过一秒,这将每秒打印一次计数。