Подтвердить что ты не робот

Java: как прервать чтение потока из System.in

У меня есть поток 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() в этом потоке, чтобы этот поток печатал Aborted.? Я пробовал System.in.close(), но это не имеет никакого значения, stdin.readline() по-прежнему блокируется.

Меня интересуют решения без

  • ожидание ожидания (потому что это сжигает 100% процессор);
  • sleep (потому что тогда программа не отвечает мгновенно на System.in).
4b9b3361

Ответ 1

Моя первая реакция заключается в том, что поток и System.in действительно не идут вместе.

Итак, сначала разделите это так, чтобы код потока не касался статического, включая System.in.

Поток читает из InputStream и переходит в буфер. Передайте InputStream в существующий поток, который читается из буфера, но также проверяет, что вы не прервали его.

Ответ 2

Информационный бюллетень Хайнца Кабуца показывает, как прервать System.in, используя buffer и ExecutorService.

Теперь я не знаю, протекает ли этот подход, не переносится или не имеет неочевидных побочных эффектов. Лично я бы не хотел его использовать.

Возможно, вы сможете что-то сделать с NIO-каналами и файловые дескрипторы - мои собственные эксперименты с ними не дали никаких результатов.

Ответ 3

Как насчет...

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

Поток, в котором вызывается stdInch.readline(), теперь прерывается, и readline() будет вызывать java.nio.channels.ClosedByInterruptException.

Ответ 4

JavaDoc для BufferedReader.readLine:

Возвращает:     Строка, содержащая содержимое строки, не включая символы окончания строки или null если конец потока был достиг

Основываясь на этом, я не думаю, что он когда-либо вернет null (может ли System.in фактически быть закрыт, я не думаю, что он когда-либо возвращает конец потока?), поэтому цикл while не будет завершен, Обычный способ остановить поток - либо использовать логическую переменную в состоянии цикла, либо изменять ее извне потока или вызывать метод прерывания() прерывания объектов (работает только в том случае, если поток wait(): ing или sleep(): ing или в методе блокировки, который генерирует InterruptedException). Вы также можете проверить, был ли поток прерван isInterrupted().

Изменить: здесь простая реализация с использованием isInterrupted() и interrupt(). Основной поток ждет 5 секунд до прерывания рабочего потока. В этом случае рабочий-поток в основном занят-ожидание, так что это не так хорошо (циклически все время и проверка stdin.ready(), вы могли бы, конечно, позволить рабочему потоку ненадолго, если вход не готов):

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;


public class MyThreadTest
{
    public static void main(String[] args)
    {
        MyThread myThread = new MyThread();
        myThread.start();

        try
        {
            Thread.sleep(5000);
        }
        catch(InterruptedException e)
        {
            //Do nothing
        }

        myThread.interrupt();

    }

    private static class MyThread extends Thread
    {       
        @Override
        public void run()
        {
            BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
            String msg;

            while(!isInterrupted())
            {
                try
                {
                    if(stdin.ready())
                    {
                        msg = stdin.readLine();
                        System.out.println("Got: " + msg);
                    }
                }
                catch(IOException e)
                {
                    e.printStackTrace();
                }
            }           
            System.out.println("Aborted.");
        }
    }

}

Кажется, что нет способа фактически прервать BufferedReader, если он заблокирован на readline, или, по крайней мере, я не смог найти его (используя System.in).

Ответ 5

Вы пробовали:

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

Метод прерывания будет вызывать InterrupedtException, и после этого вы сможете обработать код.

Ответ 6

Что касается определения поля в вашем определении класса потока выше, например:

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...
    }
  }
}