[英]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.