如何取消ConsoleReader.readLine()

OXM*_*456 10 scala jline actor

首先,我正在学习scala和java世界的新手.我想创建一个控制台并将此控制台作为可以启动和停止的服务运行.我能够将ConsoleReader运行到Actor中,但我不知道如何正确地停止ConsoleReader.这是代码:

import eu.badmood.util.trace
import scala.actors.Actor._

import tools.jline.console.ConsoleReader

object Main {

  def main(args:Array[String]){
    //start the console
    Console.start(message => {
      //handle console inputs
      message match {
        case "exit" => Console.stop()
        case _ => trace(message)
      }
    })

    //try to stop the console after a time delay
    Thread.sleep(2000)
    Console.stop()

  }

}

object Console {

  private val consoleReader = new ConsoleReader()

  private var running = false

  def start(handler:(String)=>Unit){
    running = true
    actor{
      while (running){
        handler(consoleReader.readLine("\33[32m> \33[0m"))
      }
    }
  }

  def stop(){
    //how to cancel an active call to ConsoleReader.readLine ?
    running = false
  }

}
Run Code Online (Sandbox Code Playgroud)

我也在寻找有关此代码的任何建议!

huy*_*hjl 3

从输入读取字符的底层调用是阻塞的。在非 Windows 平台上,它将System.in.read()使用org.fusesource.jansi.internal.WindowsSupport.readByte.

因此,您面临的挑战是当您想要停止控制台服务时导致阻塞调用返回。请参阅http://www.javaspecialists.eu/archive/Issue153.html是否可以从具有超时的InputStream 中读取?一些想法...一旦你弄清楚了,当你的控制台服务停止时read返回-1,这样就ConsoleReader认为它已经完成了。您需要ConsoleReader使用该调用的您的版本:

  • 如果您使用的是 Windows,您可能需要重写tools.jline.AnsiWindowsTerminal并使用ConsoleReader带有 a 的构造函数Terminal(否则AnsiWindowsTerminal将直接使用 WindowsSupport.readByte`)
  • 在unix上,有一个ConsoleReader构造函数需要一个InputStream,你可以提供你自己的包装器System.in

还有一些想法:

  • 已经有了一个scala.Console对象,因此为了减少混乱,请以不同的方式命名您的对象。
  • System.in是一种独特的资源,因此您可能需要确保Console.readLine一次只有一个调用者使用。现在start将直接呼叫readLine,并且多个呼叫者可以呼叫start。也许控制台服务可以readLine维护一个处理程序列表。

  • @OXMO456,如果您不关心在程序终止之前保留的控制台提示符,您可以做得更简单:只需在它自己的线程中启动 `ConsoleReader` 并使用 `thread.setDaemon(true)` 这样就不会阻止程序免于终止。 (2认同)