Java: как прервать чтение потока из системы.в
у меня есть поток 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% CPU);
- sleeping (потому что тогда программа не реагирует мгновенно на
System.in
).
6 ответов
моя первая реакция-это нить и System.in
действительно не идут вместе.
Итак, во-первых, разделите это так, чтобы код потока не касался статики, включая System.in
.
поток читает из InputStream
и переходит в буфер. Сдать InputStream
в существующий поток, который читает из буфера, но также проверяет, что вы не прерывается.
Хайнц Kabutz это показывает, как прервать System.in
читает с помощью буфер и ExecutorService
.
теперь я не знаю, протекает ли этот подход, не является портативным или имеет какие-либо неочевидные побочные эффекты. Лично я не хотел бы им пользоваться.
вы могли бы сделать что-то с NIO каналы и файловые дескрипторы - мои собственные эксперименты с ними не дадут результаты.
как насчет...
private static BufferedReader stdInCh = new BufferedReader(
new InputStreamReader(Channels.newInputStream((
new FileInputStream(FileDescriptor.in)).getChannel())));
какой-нить, где stdInch.readline()
вызывается теперь прерывается, и readline () будет бросать java.nio.channels.ClosedByInterruptException
.
JavaDoc для BufferedReader.readLine:
возвращает: Строка, содержащая содержимое строки, не включая символы окончания строки или null если конец потока был дошло
основываясь на этом, я не думаю, что он когда-либо вернет null (can System.на самом деле быть закрытым, я не думаю, что он когда-либо возвращает конец потока?), поэтому цикл while не завершится. Обычный способ остановить поток либо использовать логическая переменная в условии цикла и измените ее извне потока или вызовите метод interrupt ()-objects потока (работает, только если поток wait():ing или sleep():ing, или в методе блокировки, который вызывает InterruptedException). Вы также можете проверить, был ли поток прерван с помощью isInterrupted().
Edit: вот простая реализация с использованием isInterrupted()
и interrupt()
. Основной поток ожидает 5 секунд, прежде чем прервать рабочий поток. В этот рабочий поток case в основном занят ожиданием, поэтому это не так хорошо (цикл все время и проверка 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, или, по крайней мере, я не мог найти его (используя систему.в).
вы пробовали:
Thread myThread = new MyThread();
myThread.start();
// your code.
myThread.interrupt();
метод interrupt создаст исключение InterrupedtException, и после этого вы сможете обработать код.
Что касается определения поля в вашем определении класса потока выше, например:
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...
}
}
}