并发/非阻塞控制台键盘输入

8
我正在使用Java开发MUD。每个时刻我都需要读取玩家的输入,但是我正在使用的Scanner使用的是阻塞操作。我想要实现非阻塞输入。
我研究了nio包中的Selector类,但是我不确定如何将其与System.in结合使用。我想一旦我运行服务器就一定会需要它,但目前所有操作都是脱机的。
我尝试从Applet扩展主类并重写keyDown方法,但这只意味着在第一个输入之后再也无法接受输入了。虽然我不再阻塞任何操作,但却再也没有输入。我猜keyDown再也不会被调用了。
也许线程在执行阻塞操作时可以被中断?
感谢对此问题的任何见解。

非阻塞套接字(网络编程)的实现方式与非阻塞IO并不相同,至少在大多数环境中是这样。 - Textmode
4个回答

2

由于现在无法以多平台方式完成,因此您无法使用系统控制台进行操作。

您可以使用Swing窗口作为控制台或找到基于JNI的方法,但这可能无法在某些平台上工作。

您可以使用JCurses。它可能有效,它基于JNI并支持Windows和Linux。


JCursesжҳҜеҹәдәҺUNIXзҡ„cursesжһ„е»әзҡ„пјҢеӣ жӯӨе®ғиӮҜе®ҡеҸҜд»Ҙе·ҘдҪңгҖӮ - H2ONaCl
截至2014年5月23日,“解释”链接已失效(现在链接到域名停放页面)。 - daveloyall
@daveloyall 我已经将它移除了。谢谢。 - aalku

0

keyDown()已经弃用,我建议使用processKeyEventkeyListener代替。

也许即使在执行阻塞操作时,线程也可以被中断?

是的,如果您有要中断的线程对象的引用,只需在该实例上调用interrupt()方法即可。在线程的run方法中,您可以处理中断异常。但是,这似乎有点hack-ish。我不认为这比使用简单的KeyListener更有帮助。


Thread.interrupt() 只设置中断标志并唤醒线程,如果它正在睡眠或阻塞。它不会中断常规的阻塞文件 IO 或套接字读取。它也不会中断大量计算或自旋锁 - 您的代码需要检查并遵守“已中断”标志以使其可中断。 - ddimitrov

-1

我曾经不得不解决过与http阻塞写入/读取类似的问题。在那种情况下,我使用了本地缓冲区和线程。

思路很简单,一个线程从stdin读取并将内容放入缓冲区。第二个线程进行相同的写入操作。

然后,您可以对缓冲区进行非阻塞查询。

示例代码:

class NonBlockingReader implements Runnable{
  Reader in;
  List buffer;
  public void run(){
    String line=null;
    while((line=in.readLine())!=null){
      storeLine(line);
    }
  }
  private synchronized storeLine(String line){
    buffer.add(line);
  }
  public synchronized String getLine(){
    if(list.size()>0)
       return list.removeFirst();
    return null;
  }
}

// .. same for writer, then you jast pass stdin and stdout ...

System.in流是Java的标准输入(stdin)等效流,它是带缓冲区的,因此应用程序在用户按下回车键之前看不到字符。 - ddimitrov

-1

1
downvote: 上述链接引用了 ConsoleReader.readVirtualKey,它是一个阻塞操作。 - H2ONaCl

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接