簡體   English   中英

線程中的阻塞方法

[英]Blocking method in Thread

我正在嘗試為國際象棋開發計時器。 應該有一個像

等待用戶輸入從控制台移到那里

如果等待時間> 60

停止等待並繼續前進。

我能想到的解決方案是使用Thread這樣的:

public class Game {
  Thread t1 = new PlayDisc(this);
  Thread t2 = new Timer(this);

  public static void main(String[] args) {
    t1.start();
    t2.start();
  }
}


public class Timer extends Thread{
   Game g;


  public Timer(Game g) {
    this.g = g;
  }

@Override
  public void run() {
    int i = 0;
    while(true){
      if(i > 6000) {
        g.t1.interrupt();
        break;
      }
    }
  }
}

public class PlayDisc extends Thread{
  private Game g;

  public PlayDisc(Game g) {
    this.g = g;
  }

  @Override
  public void run() {
    Scanner s = new Scanner(System.in);

    int x = s.nextInt();
    int y = s.nextInt();

    Point p = new Point(x, y);
    cm.nextPoint = p;
    s.close();
  }


}

我知道這將不起作用,因為Scanner.nextInt()是一種阻止方法。 但是我需要從cmd行讀取輸入。 有什么辦法解決這個問題?

已經存在一個Timer類(實際上是其中的兩個, java.util.Timerjavax.swing.Timer )。 但是,正如您已經意識到的那樣, nextInt()的阻塞性質使您無法在超時后執行任何操作。 您將需要一個額外的庫,該庫將提供比默認情況下Java更好的控制台控制。 那,或者使用Swing

編輯:通過使用具有hasNextInt()的輪詢循環,可能會執行某種形式的黑客攻擊。 這樣,您就不會讓掃描線程阻塞。

重新編輯:不,這是不可能的,因為hasNext()會阻塞。 您必須測試中斷是否會使您擺脫麻煩(可能不會)。

Scanner的問題在於您無法控制該方法讀取更多字節,而這總是會導致阻塞。 安全的方法是手動從System.in讀取並創建一個Scanner ,該Scanner只能讀取您已經從控制台獲取的字節。 然后,您可以進行輪詢(在睡眠狀態下)以實現超時。 通過選擇合適的睡眠時間,您可以在響應速度和CPU使用率之間獲得適當的平衡。

下面的示例程序使用200ms的檢查間隔,該間隔足以被人類用戶感知為“立即響應”。 該值與您可以自由配置的等待時間無關(只要它顯着高於檢查間隔)。

要注意的其他事情是,我們在開始時就計算了最后期限,而不是匯總等待時間以獨立於循環中的CPU使用率。 而且我們使用System.nanoTime()來獨立於系統時鍾可能發生的變化。

long timeOutNS=TimeUnit.MINUTES.toNanos(1); // 1 min timeout
long checkNS=TimeUnit.MILLISECONDS.toNanos(200); // check input every 200ms

int input=0;
boolean hasInput=false;

readWithTimeOut: {
  System.out.println("Enter int: ");
  long deadLine=System.nanoTime() + timeOutNS;
  for(;;) {
    int a = System.in.available();
    if(a>0) {
      byte[] b=new byte[a];
      a=System.in.read(b);
      if(a<=0) break readWithTimeOut;
      Scanner scanner=new Scanner(new ByteArrayInputStream(b, 0, a));
      if(scanner.hasNextInt()) {
        input=scanner.nextInt();
        hasInput=true;
        break;
      }
      else if(scanner.hasNext())
        System.err.println("not an int: "+scanner.next()); // consumes token
      continue;
    }
    long remaining=deadLine-System.nanoTime();
    if(remaining<=0) {
      System.err.println("timeout");
      break readWithTimeOut;
    }
    LockSupport.parkNanos(Math.min(remaining, checkNS));
  }
}

System.out.println( hasInput? "entered "+input: "no valid input" ); 

InputStream.available()是一種非阻塞方法,可用於檢查流中是否有內容。 如果您不關心旋轉(從而浪費處理器內核),那么就可以這么簡單:

import java.io.IOException;
import java.util.Scanner;

public class ConsoleReadWithTimeout {

    static Scanner scanner = new Scanner(System.in);

    public static void main(String[] args)  throws Exception {

        int i = readIntWithTimeout(5 * 1000);

        scanner.close();
    }
    // returns -1 in case of timeout
    static private int readIntWithTimeout(long timeoutInMs) throws IOException {
        long startTime = System.currentTimeMillis();
        while (System.in.available() == 0) {
            if (timeoutInMs < System.currentTimeMillis() - startTime) {
                return -1; // or maybe throw a TimeoutException ?
            }
        }
        return scanner.nextInt();
    }
}

暫無
暫無

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

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