while 循环不循环/显示计数
while loop not looping / displaying count
此方法重复读取命令并执行它们,直到游戏结束。 finished 变量,当为真时,意味着 player/user 已经点击退出并想要结束游戏 - 从而退出循环并执行到方法结束。
import org.apache.commons.lang3.time.StopWatch;
private Parser parser;
private Command command;
private StopWatch stopWatch;
public void play()
{
stopWatch = new StopWatch();
stopWatch.start();
long timeLimit = 5000;
boolean finished = false;
printWelcome();
while (finished == false)
{
System.out.println(stopWatch.getTime() + " milliseconds");
if (stopWatch.getTime() >= timeLimit)
{
System.out.println("Time limit of " + timeLimit + " milli seconds has been reached. Good bye!");
return;
}
else
{
command = parser.getCommand();
finished = processCommand(command);
}
}
System.out.println("Thank you for playing. Good bye.");
}
但是我观察到循环有一个奇怪的行为。它循环得很好(当省略以下行时显示 stopWatch.getTime() 的连续计数:
else
{
command = parser.getCommand();
finished = processCommand(command);
}
但是当我把它们放回去时,它停止显示秒表的连续递增时间,因为它增加到 timeLimit(此时,它应该停止)。即使玩家没有输入任何命令或输入。
秒表显然在后台运行,但它不显示计数。
请指教。谢谢。
我认为您的 parser.getCommand();
在输入之前一直处于阻塞状态。由于这个 while 循环在一个线程中运行,程序在此时停止。
检查我是否正确的最简单方法是输入任何命令,你应该从这一行得到一些输出:
System.out.println(stopWatch.getTime() + " milliseconds");
您要么需要在此方法中实现超时,要么有第二个线程计算时间并中断等待。
Even if the player hasn't entered any command or input.
如果Parser#getCommand
是一个等待用户输入的方法,执行将阻塞直到用户输入。这意味着 while
循环不会 运行 并且您不会看到它打印出新时间。
不管怎样,按照您的要求进行操作会给用户带来非常不愉快的体验,因为这意味着在他们输入命令时它会继续打印,这对用户来说不是很友好。
您可以为此使用 producer-consumer approach。我改编了链接问题中的代码:
// Shared queue
final Queue<String> commands = new ConcurrentLinkedQueue<>();
// Non-blocking consumer
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
executor.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
// non-blocking
if((String command = commands.poll()) != null) {
processCommand(command);
}
}
}, 0, 10, TimeUnit.MILLISECONDS);
// Blocking producer (this is basically the logic from Parser#getCommand)
Scanner sc = new Scanner(System.in);
while(sc.hasNext()) {
commands.add(sc.next());
}
但是,此解决方案并不能真正让您实现超时。所以你必须创建一个新的 class "wraps" Runnable
以便你可以在超时后取消它(类似于 this 方法):
public class TimeOutableRunnable implements Runnable {
private final Queue<String> commands;
private final Runnable wrapped;
private volatile ScheduledFuture<?> self;
public TimeOutableRunnable(Runnable wrapped, Queue<String> commands) {
this.commands = commands;
this.wrapped = wrapped;
}
@Override
public void run() {
if(commands.isEmpty()) {
self.cancel(false);
} else {
wrapped.run();
}
}
public void runWithTimeout(ScheduledExecutorService executor, long timeout, TimeUnit unit) {
self = executor.scheduleAtFixedRate(this, 0, timeout, unit);
}
}
那么你可以这样做:
final Queue<String> commands = new ConcurrentLinkedQueue<>();
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
new TimeOutableRunnable(new Runnable() {
@Override
public void run() {
// non-blocking
while((String command = commands.poll()) != null) {
processCommand(command);
}
}
}, commands).runWithTimeout(executor, timeLimit, TimeUnit.MILLISECONDS);
我还没有对此进行测试,我不会对自己的并发性评价很高,所以如果这种方法存在根本性错误,请告诉我。
也许我误解了你的问题,但它不是连续打印这听起来像是你的问题?如果是这样,那是因为您的解析器正在等待用户输入。线程可以解决这个问题,运行 你的计时器和打印在一个单独的线程中
此方法重复读取命令并执行它们,直到游戏结束。 finished 变量,当为真时,意味着 player/user 已经点击退出并想要结束游戏 - 从而退出循环并执行到方法结束。
import org.apache.commons.lang3.time.StopWatch;
private Parser parser;
private Command command;
private StopWatch stopWatch;
public void play()
{
stopWatch = new StopWatch();
stopWatch.start();
long timeLimit = 5000;
boolean finished = false;
printWelcome();
while (finished == false)
{
System.out.println(stopWatch.getTime() + " milliseconds");
if (stopWatch.getTime() >= timeLimit)
{
System.out.println("Time limit of " + timeLimit + " milli seconds has been reached. Good bye!");
return;
}
else
{
command = parser.getCommand();
finished = processCommand(command);
}
}
System.out.println("Thank you for playing. Good bye.");
}
但是我观察到循环有一个奇怪的行为。它循环得很好(当省略以下行时显示 stopWatch.getTime() 的连续计数:
else
{
command = parser.getCommand();
finished = processCommand(command);
}
但是当我把它们放回去时,它停止显示秒表的连续递增时间,因为它增加到 timeLimit(此时,它应该停止)。即使玩家没有输入任何命令或输入。
秒表显然在后台运行,但它不显示计数。
请指教。谢谢。
我认为您的 parser.getCommand();
在输入之前一直处于阻塞状态。由于这个 while 循环在一个线程中运行,程序在此时停止。
检查我是否正确的最简单方法是输入任何命令,你应该从这一行得到一些输出:
System.out.println(stopWatch.getTime() + " milliseconds");
您要么需要在此方法中实现超时,要么有第二个线程计算时间并中断等待。
Even if the player hasn't entered any command or input.
如果Parser#getCommand
是一个等待用户输入的方法,执行将阻塞直到用户输入。这意味着 while
循环不会 运行 并且您不会看到它打印出新时间。
不管怎样,按照您的要求进行操作会给用户带来非常不愉快的体验,因为这意味着在他们输入命令时它会继续打印,这对用户来说不是很友好。
您可以为此使用 producer-consumer approach。我改编了链接问题中的代码:
// Shared queue
final Queue<String> commands = new ConcurrentLinkedQueue<>();
// Non-blocking consumer
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
executor.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
// non-blocking
if((String command = commands.poll()) != null) {
processCommand(command);
}
}
}, 0, 10, TimeUnit.MILLISECONDS);
// Blocking producer (this is basically the logic from Parser#getCommand)
Scanner sc = new Scanner(System.in);
while(sc.hasNext()) {
commands.add(sc.next());
}
但是,此解决方案并不能真正让您实现超时。所以你必须创建一个新的 class "wraps" Runnable
以便你可以在超时后取消它(类似于 this 方法):
public class TimeOutableRunnable implements Runnable {
private final Queue<String> commands;
private final Runnable wrapped;
private volatile ScheduledFuture<?> self;
public TimeOutableRunnable(Runnable wrapped, Queue<String> commands) {
this.commands = commands;
this.wrapped = wrapped;
}
@Override
public void run() {
if(commands.isEmpty()) {
self.cancel(false);
} else {
wrapped.run();
}
}
public void runWithTimeout(ScheduledExecutorService executor, long timeout, TimeUnit unit) {
self = executor.scheduleAtFixedRate(this, 0, timeout, unit);
}
}
那么你可以这样做:
final Queue<String> commands = new ConcurrentLinkedQueue<>();
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
new TimeOutableRunnable(new Runnable() {
@Override
public void run() {
// non-blocking
while((String command = commands.poll()) != null) {
processCommand(command);
}
}
}, commands).runWithTimeout(executor, timeLimit, TimeUnit.MILLISECONDS);
我还没有对此进行测试,我不会对自己的并发性评价很高,所以如果这种方法存在根本性错误,请告诉我。
也许我误解了你的问题,但它不是连续打印这听起来像是你的问题?如果是这样,那是因为您的解析器正在等待用户输入。线程可以解决这个问题,运行 你的计时器和打印在一个单独的线程中