我有以下线程,每200ms只打印一个点:
public class Progress {
private static boolean threadCanRun = true;
private static Thread progressThread = new Thread(new Runnable()
{
public void run() {
while (threadCanRun) {
System.out.print('.');
System.out.flush();
try {
progressThread.sleep(200);
} catch (InterruptedException ex) {}
}
}
});
public static void stop()
{
threadCanRun = false;
progressThread.interrupt();
}
public static void start()
{
if (!progressThread.isAlive())
{
progressThread.start();
} else
{
threadCanRun = true;
}
}
}
我使用此代码启动线程(暂时):
System.out.println("Working.");
Progress.start();
try {
Thread.sleep(10000); //To be replaced with code that does work.
} catch (InterruptedException ex) {}
Progress.stop();
这真是奇怪:
如果我使用System.out.println('.');
,则代码完全按预期工作。 (除了我每次都不想要新线路这一事实。)
使用System.out.print('.');
,代码等待十秒钟,然后显示输出。
System.out.println
:
Print dot, wait 200ms, print dot, wait 200ms etc...
System.out.print
:
Wait 5000ms, Print all dots
发生了什么,我该怎么做才能绕过这种行为?
修改
我也试过这个:
private static synchronized void printDot()
{
System.err.print('.');
}
和printDot()而不是System.out.print('.');
它仍然无效。
EDIT2:
有趣。此代码按预期工作:
System.out.print('.');
System.out.flush(); //Makes no difference with or without
System.out.println();
这不是:
System.err.print('.');
System.err.flush();
System.out.print('.');
System.out.flush();
解决方案:问题与netbeans有关。当我从java -jar中将它作为jar文件运行时,它工作正常。
这是我一生中见过的最令人沮丧的错误之一。当我尝试在调试模式下使用断点运行此代码时,一切正常。
答案 0 :(得分:5)
stdout是行缓冲的。 使用stderr,或在每次打印后刷新PrintStream。
答案 1 :(得分:4)
(这是奇怪的代码 - 有更简洁的方法来编写和管理线程。但是,这不是问题。)
您的IDE必须按行缓冲。尝试直接在命令行上运行它。 (并希望shell也不会缓冲,但不应该。)
答案 2 :(得分:1)
println
方法自动刷新输出缓冲区,而不是print
方法。如果您想立即查看输出,可以拨打System.out.flush
电话。
答案 3 :(得分:1)
我认为这是因为println()方法是同步的
答案 4 :(得分:1)
(这不是答案;提问者大卫要求我跟进关于重写线程的第二点。我只能以这种方式发布代码。)
public class Progress {
private ProgressRunnable progressRunnable = new ProgressRunnable();
public void start() {
new Thread(progressRunnable).start();
}
public void stop() {
progressRunnable.stop();
}
private class ProgressRunnable implements Runnable {
private final AtomicBoolean running = new AtomicBoolean(true);
@Override
public void run() {
while (running.get()) {
System.out.print('.');
System.out.flush();
try {
Thread.sleep(200);
} catch (InterruptedException e) {
}
}
}
private void stop() {
running.set(false);
}
}
public static void main(String[] args) {
Progress progress = new Progress();
progress.start();
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
}
progress.stop();
}
}
答案 5 :(得分:0)
我使用System.out.print()
和System.out.flush()
测试了您的代码。该代码适用于我,代码除外:
while (!threadCanRun)
{
Thread.yield();
}
进展课程。这样做,线程正在暂停,允许其他线程执行,正如您在线程api page中看到的那样。删除此部分,代码可以正常工作。
但我不明白为什么你需要yield
方法。如果您致电Progress.stop()
,则会导致调用yield
方法。线程将以interrupt
停止后(在我的电脑上等待了大量时间之后)。
如果要允许其他线程执行并且当前线程暂停,请考虑join()
方法。
如果你想停止当前线程,也许你可以考虑删除
while(!threadCanRun)
循环Thread.currentThread().join()
或Thread.interrupt()
stop()
之前的p.stop()
等待完成其他线程,或只是调用{{1}}方法。
看看这些posts。