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