Java 线程中的阻塞方法
我想为国际象棋比赛设计一个计时器。 应该有这样一个函数 等待用户输入,然后从控制台移动 如果等待时间>60 停止等待,继续前进 我能想到的解决方法是使用线程:Java 线程中的阻塞方法,java,multithreading,Java,Multithreading,我想为国际象棋比赛设计一个计时器。 应该有这样一个函数 等待用户输入,然后从控制台移动 如果等待时间>60 停止等待,继续前进 我能想到的解决方法是使用线程: public class Game { Thread t1 = new PlayDisc(this); Thread t2 = new Timer(this); public static void main(String[] args) { t1.start(); t2.start(); } } p
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()是一种阻塞方法。但我需要从命令行读取输入。
有什么办法解决这个问题吗 已经有一个
Timer
类(实际上有两个,java.util.Timer
和javax.swing.Timer
)。但正如您所意识到的,nextInt()
的阻塞特性阻止您在超时后执行任何操作。您将需要一个额外的库,它将为您提供比默认情况下Java更好的控制台控制。或者使用Swing
编辑:通过使用带有hasNextInt()
的轮询循环,可以执行某种类型的黑客攻击。这样就不会让扫描线程阻塞
重新编辑:不,这是不可能的,因为hasNext()将被阻止。您必须测试中断是否能帮您摆脱这里的麻烦(可能不会)。已经有了
计时器类(实际上有两个,java.util.Timer
和javax.swing.Timer
)。但正如您所意识到的,nextInt()
的阻塞特性阻止您在超时后执行任何操作。您将需要一个额外的库,它将为您提供比默认情况下Java更好的控制台控制。或者使用Swing
编辑:通过使用带有hasNextInt()
的轮询循环,可以执行某种类型的黑客攻击。这样就不会让扫描线程阻塞
重新编辑:不,这是不可能的,因为hasNext()将被阻止。您必须测试中断是否能让您摆脱这里的麻烦(可能不会)。扫描仪的问题是您无法控制方法读取更多字节,这可能会导致阻塞。安全的方法是从系统中手动读取。在
中,创建一个扫描仪
,它只能读取您已经从控制台获得的字节。然后,您可以进行轮询(使用睡眠)来实现超时。通过选择适当的睡眠时间,您可以在响应能力和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" );
long timeOutNS=TimeUnit.MINUTES.toNanos(1);//1分钟超时
long checkNS=时间单位。毫秒。toNanos(200);//每200ms检查一次输入
int输入=0;
布尔输入=假;
readWithTimeOut:{
System.out.println(“输入int:”);
长截止日期=System.nanoTime()+超时;
对于(;;){
int a=系统中的可用();
如果(a>0){
字节[]b=新字节[a];
a=系统英寸读数(b);
如果(aScanner
的问题是您无法控制该方法读取更多字节,这通常会导致阻塞。安全的方法是从系统中手动读取。在中,创建一个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" );
long timeOutNS=TimeUnit.MINUTES.toNanos(1);//1分钟超时
long checkNS=时间单位。毫秒。toNanos(200);//每200ms检查一次输入
int输入=0;
布尔输入=假;
readWithTimeOut:{
System.out.println(“输入int:”);
长截止日期=System.nanoTime()+超时;
对于(;;){
int a=系统中的可用();
如果(a>0){
字节[]b=新字节[a];
a=系统英寸读数(b);
if(aInputStream.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();
}
}
import java.io.IOException;
导入java.util.Scanner;
公共类ConsoleReadWithTimeout{
静态扫描仪=新扫描仪(System.in);
公共静态void main(字符串[]args)引发异常{
int i=带超时的readIntWithTimeout(5*1000);
scanner.close();
}
//超时时返回-1
静态私有int readIntWithTimeout(长时间超时)引发IOException{
long startTime=System.currentTimeMillis();
while(System.in.available()==0){
if(timeoutims
InputStream.available()
是一种非阻塞方法,可用于检查流中是否有内容。
如果你不在乎旋转(和t