[英]How to create a threaded console progress bar in Java?
我正在尝试用Java创建一个可运行的进度栏程序,以便它可以支持控制台和GUI应用程序。
这个想法是使用线程来提供当前的进度信息,但是似乎线程代码无法正常工作。 并发对我来说太新了。
我希望它每次向上移动一次,而不是在进度条赶上之前过早地完成循环。 我猜问题出在时间上吗?
[=====> ] 10% 1
2
3
4
5
6
7
8
9
10
[==================================================] 100%
有人可以告诉我我出了什么问题吗?
主要代号
package console;
import java.util.ArrayList;
import console.ProgressThread;
public class ConsoleProgressBar
{
private static final long REFRESH_DELAY = 50;
private ProgressValue progress;
private ProgressThread target;
private Thread thread;
protected static class ProgressValue
{
protected long total = 0;
protected long current = 0;
protected ProgressValue(long n)
{
total = n;
}
protected synchronized void setMaxTotal(long n)
{
total = n;
}
protected synchronized void stepBy(long n)
{
current = current + n;
if (current > total) total = current;
}
protected synchronized void stepTo(long n)
{
current = n;
if (current > total) total = current;
}
protected synchronized long getCurrent()
{
return current;
}
protected synchronized long getTotal()
{
return total;
}
}
public ConsoleProgressBar(long totalItem)
{
this(totalItem, REFRESH_DELAY);
}
public ConsoleProgressBar(long totalItem, long refreshDelay)
{
progress = new ProgressValue(totalItem);
target = new ProgressThread(progress, refreshDelay);
}
public void start()
{
thread = new Thread(target);
thread.start();
}
public void stepBy(long n)
{
progress.stepBy(n);
}
public void stepTo(long n)
{
progress.stepTo(n);
}
public void step()
{
progress.stepBy(1);
}
public void setMaxTotal(long n)
{
progress.setMaxTotal(n);
}
public void stop()
{
target.terminate();
try
{
thread.join();
}
catch (InterruptedException ex)
{
}
}
public long getCurrent()
{
return progress.getCurrent();
}
public long getTotal()
{
return progress.getTotal();
}
public static void main(String[] args)
{
ArrayList<Integer> test = new ArrayList<>();
ConsoleProgressBar bar = new ConsoleProgressBar(10, 50);
bar.start();
for (int i = 0; i < 10; i++)
{
int sum = i + 5;
test.add(sum);
bar.step();
System.out.format("%s%n", bar.getCurrent());
}
bar.stop();
}
}
线程代码
package console;
import console.ConsoleProgressBar.ProgressValue;
public class ProgressThread implements Runnable
{
private static final int WIDTH = 50;
private volatile boolean terminated;
private ProgressValue progressRef;
private long timeMS;
public ProgressThread(ProgressValue ref, long refreshDelay)
{
progressRef = ref;
timeMS = refreshDelay;
terminated = false;
}
private void refreshProgressBar()
{
StringBuilder sb = new StringBuilder("\r[");
int percent = (int) Math.floor(100.0 * progressRef.current / progressRef.total);
for (int i = 0; i < WIDTH; i++)
{
if (i < (percent / 2)) sb.append("=");
else if (i == (percent / 2)) sb.append(">");
else sb.append(" ");
}
sb.append("] %s ");
if (percent >= 100) sb.append("%n");
System.out.printf(sb.toString(), percent + "%");
}
void terminate()
{
terminated = true;
}
public void run()
{
try
{
while (terminated == false)
{
refreshProgressBar();
Thread.sleep(timeMS);
}
refreshProgressBar();
}
catch (InterruptedException exc)
{
}
}
}
当您仅想完成一项任务时,为什么需要多线程应用程序?
尽管如此,要实现所需的目标,我建议将执行完全移入线程类或主类。
如果主应用程序将要运行其他程序,那么理想情况下,您应将执行放在线程类中。 但是在这里,我已将执行放入主类。 它也可以很容易地进入线程类。
举例来说,我在ProgressThread
编辑了run()
就是这样,
public void run()
{
while( terminated )
{
}
}
然后我在ConsoleProgressBar
编辑了main
public static void main(String[] args)
{
ArrayList<Integer> test = new ArrayList<>();
ConsoleProgressBar bar = new ConsoleProgressBar(10, 50);
bar.start();
for (int i = 0; i <= 10; i++)
{
int sum = i + 5;
test.add(sum);
bar.refreshProgressBar();
System.out.format( "%s", bar.getCurrent() );
bar.step();
bar.sleep( 1000 );
}
bar.stop();
}
请注意,我将方法sleep( int n )
和refreshProgressBar()
到bar中,以便可以调用线程方法,类似于您对bar.start()
和bar.stop()
。
为清楚起见,仅出于示例目的,在ProgressThread
我将refreshProgressBar
更改为public
,并添加了以下内容:
void sleep( int n )
{
try
{
Thread.sleep( n );
}
catch( InterruptedException ie )
{
ie.printStackTrace();
}
}
以及以下ConsoleProgressBar
,
private void sleep( int n )
{
target.sleep( n );
}
private void refreshProgressBar()
{
target.refreshProgressBar();
}
输出(每行打印间隔为一秒)为:
[> ] 0% 0
[=====> ] 10% 1
[==========> ] 20% 2
[===============> ] 30% 3
[====================> ] 40% 4
[=========================> ] 50% 5
[==============================> ] 60% 6
[===================================> ] 70% 7
[========================================> ] 80% 8
[=============================================> ] 90% 9
[==================================================] 100% 10
不确定这是否是您要查找的内容,但我建议将执行结果放到一个地方。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.