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
).
Ответы
Ответ 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...
}
}
}