簡體   English   中英

while循環不循環/顯示計數

[英]while loop not looping / displaying count

此方法反復讀取命令並執行它們,直到游戲結束。 Finished變量為true時,表示玩家/用戶已按下Quit並想要結束游戲-因此退出循環並執行到方法結束。

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); 
  }

但是當我把它們放回去時,它會停止顯示stopWatch的連續遞增時間,因為它朝着timeLimit遞增(此時,它應該停止)。 即使播放器沒有輸入任何命令或輸入。

秒表顯然在后台運行,但是不顯示計數。

請指教。 謝謝。

即使播放器沒有輸入任何命令或輸入。

如果Parser#getCommand是等待用戶輸入的方法,則執行將阻塞,直到用戶輸入輸入為止。 這意味着while循環將不會運行,並且您不會看到它打印出新的時間。

無論如何,執行您要求的操作都會給用戶帶來非常刺耳的體驗,因為這將意味着在用戶鍵入命令時它將繼續打印,並且這不是非常用戶友好的。

您可以為此使用生產者-消費者方法 我已經根據鏈接的問題改編了代碼:

// 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());
}

但是,此解決方案並不能真正讓您實現超時。 因此,您將必須創建一個新類來“包裝” Runnable以便在超時后可以將其取消(類似於方法):

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);

我還沒有對此進行測試,因此我對並發性評價不高,所以請告訴我這種方法是否存在根本性的錯誤。

我假設您的parser.getCommand(); 在輸入之前一直處於阻塞狀態。 當while循環在一個線程中運行時,程序將在此時停止。

檢查我是否正確的最簡單方法是輸入任何命令,並且您應該從此行獲得一些輸出:

       System.out.println(stopWatch.getTime() + " milliseconds");

您或者需要在此方法中實現超時,或者需要第二個線程對時間進行計數並中斷等待。

也許我誤會了您的問題,但是聽起來好像您的問題是它不是連續打印的? 如果是這樣,那是因為您的解析器正在等待用戶輸入。 線程可以解決此問題,運行計時器並在單獨的線程中打印

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM