Java:如何中止从System.in读取线程

Java:如何中止从System.in读取线程,java,stdio,Java,Stdio,我有一个Java线程: class MyThread extends Thread { @Override public void run() { BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in)); String msg; try { while ((msg = stdin.readLine()) != null) {

我有一个Java线程:

class MyThread extends Thread {
  @Override
  public void run() {
    BufferedReader stdin =
        new BufferedReader(new InputStreamReader(System.in));
    String msg;
    try {
      while ((msg = stdin.readLine()) != null) {
        System.out.println("Got: " + msg);
      }
      System.out.println("Aborted.");
    } catch (IOException ex) {
      ex.printStackTrace();
    }
  }
}
}

在另一个线程中,如何中止此线程中的
stdin.readline()
调用,以便此线程打印
已中止。
?我已经尝试了
System.in.close()
,但是没有任何区别,
stdin.readline()
仍在阻塞

我对解决方案感兴趣,没有

  • 忙等待(因为这会消耗100%的CPU)
  • 休眠(因为程序不会立即响应
    System.in
    • 返回: 包含行内容的字符串,不包括任何 行终止字符,或null 如果流的结尾已被删除 达到

      基于此,我认为它永远不会返回null(System.in是否真的可以关闭,我认为它永远不会返回流的结尾?),因此while循环不会终止。停止线程的常用方法是在循环条件中使用布尔变量并从线程外部对其进行更改,或者调用线程对象的interrupt()-方法(仅当线程为wait():ing或sleep():ing,或者在抛出InterruptedException的阻塞方法中工作)。您还可以检查线程是否已被中断

      编辑:下面是一个利用
      isInterrupted()
      interrupt()
      的简单实现。主线程在中断工作线程之前等待5秒。在这种情况下,工作线程基本上都在忙着等待,所以没有那么好(一直循环并检查
      stdin.ready()
      ,如果没有准备好输入,当然可以让工作线程休眠一段时间):


      如果BufferedReader在readline上被阻止,或者至少我找不到它(使用System.in),那么似乎没有办法实际中断它。

      在上面的线程类定义中定义一个字段,比如:

      class MyThread extends Thread {   
      
        protected AtomicBoolean abortThread = new AtomicBoolean(false);
      
        public void doAbort()
        {
          this.abortThread.set(true);
        }
      
        @Override   public void run() 
        { 
          ...
          if (this.abortThread.get())
          {
            ...something like break loop...
          }
        }
      }
      
      您是否尝试过:

      Thread myThread = new MyThread();
      myThread.start();
      // your code.
      myThread.interrupt();
      

      中断方法将抛出InterrupedException,然后您可以处理代码。

      我的第一反应是线程和
      系统。在
      中,线程和
      真的不在一起

      因此,首先,将其拆分,以便线程代码不会接触任何静态对象,包括
      System.in

      线程从
      InputStream
      读取数据,并将其传递到缓冲区。将
      InputStream
      传递到现有线程中,该线程从缓冲区读取数据,但也检查您是否已中止

      显示如何中止
      系统。在
      中使用and进行读取

      现在,我不知道这种方法是否泄漏、不可移植或有任何不明显的副作用。就我个人而言,我不愿意使用它

      你也许可以用它们做点什么-我自己用它们做的实验没有产生任何结果。

      怎么样

      private static BufferedReader stdInCh = new BufferedReader(
          new InputStreamReader(Channels.newInputStream((
          new FileInputStream(FileDescriptor.in)).getChannel())));
      

      调用
      stdInch.readline()
      的线程现在是可中断的,并且readline()将抛出一个
      java.nio.channels.closedbyinterrupexception

      。了解如何中止侦听传入客户端套接字数据的线程也很有意思。希望解决方案与这个问题非常相似:)这是一个从stdin读取的更一般的问题-java.io的东西阻塞了I/O,关于这个更一般的问题存在很多问题。@Ancide:对于套接字,我有一个解决方案:关闭另一个线程中的套接字会使
      MyThread
      中的
      readLine
      引发
      SocketException
      ,其中
      为“socketclosed”
      。因此,我可以通过这种方式中止MyThread。Solaris上曾短暂启用过可中断I/O,但通常不起作用。(不管怎样,中断都很可怕。)这很可怕,但他问:我如何中止stdin.readline(),所以,这是一种方法。在这个线程中读取System.in的想法是错误的。“中止”并不一定意味着Java线程中断机制。谢谢你提出这个建议,但它对我不起作用<代码>myThread.interrupt()
      没有任何区别
      stdin.readLine()
      仍被阻止,等待从
      中的
      系统读取更多输入。在实际读取流之前调用System.in.ready()是否有帮助?@user625146:感谢您提出建议,但它不起作用。我看不出设置
      abortThread
      将如何中止对
      System.in.readline()
      @user625146的调用:如果ready()返回false怎么办?如何让MyThread在不忙的情况下等待下一行(100%CPU使用)?以预定义的时间量让线程进入睡眠状态。这可以通过第二个环绕while循环来完成。只有当读卡器准备就绪时,才能进入read while循环,否则将线程置于睡眠状态。这行吗?谢谢你写下你的答案,但它不能解决我的问题。调用
      myThread.interrupt()
      不会中断
      System.in
      上的
      readLine()
      调用,即使在
      System.in.close()之后也不会在Windows上工作。Windows在ready()期间不回显输入,因此不适用于交互式解决方案。感谢您建议不要在线程中使用静态,这是一个很好的编码风格改进。但这也与我的问题无关。“还要检查您是否已中止”-是的,这正是我想做的,但我不知道在线程被阻塞时如何执行
      stdin.readLine()
      。请您详细说明一下好吗?@pts静态数据与您的问题相关两个线程:一个从流中读取,并在I/O上阻塞;一个(您现有的线程)从缓冲区读取数据,并在锁上阻塞数据。如果能看到一些实现这一思想的示例代码,那就太好了。你的描述有点模糊。我回答了一个问题,并提供了一些使用PipedInputStream作为示例的简单代码。感谢您的建议。我也认为它可以在某种程度上与NIO一起工作,但是重写我的程序以使用NIO太费事了,所以我现在正在寻找其他的选择。
      private static BufferedReader stdInCh = new BufferedReader(
          new InputStreamReader(Channels.newInputStream((
          new FileInputStream(FileDescriptor.in)).getChannel())));