2013-10-02 2 views
2

У меня есть поток, который читает ввод пользователя и отправляет его по сети. Нить сидит в петле, как это:Возможно ли прервать Scanner.hasNext()

sin = new Scanner(System.in); 

while (sin.hasNextLine()) { 
    if (this.isInterrupted()) 
     break; 

    message = sin.nextLine(); 

    // do processing...   
} 

Но когда я пытаюсь прервать нить не выйти из метода hasNextLine().

Как я могу выйти из этого цикла?

+0

может быть, для этой ситуации делают, в то время как цикл будет иметь больше смысла. просто пропустите первую итерацию и как условие сделайте .. while (sin.hasNextLine() &&! this.isInterrupted()) –

+0

Но это не решает проблему - поток по-прежнему заблокирован в вызове hasNextLine() ... – dmitru

ответ

5

Попробуйте заменить грех. hasNextLine со следующим методом. Идея заключается в том, чтобы не вводить операцию чтения блокировки, если в ней нет данных.

У меня такая же проблема давным-давно, и это исправляет ее. В принципе, когда вы выполняете System.in.read() в потоке и из другого потока, вы пытаетесь его прервать, это не сработает, если вы не нажмете Enter. Вы можете подумать, что нажатие любого символа должно работать, но это не так, потому что кажется, что операция чтения внутри os (или слоя абстракции аппаратного jvm) возвращает только полные строки.

Даже System.in.available() не вернет ненулевое значение, если вы не нажмете Enter, насколько я знаю.

private boolean hasNextLine() throws IOException { 
    while (System.in.available() == 0) { 
     // [variant 1 
     try { 
      Thread.currentThread().sleep(10); 
     } catch (InterruptedException e) { 
      System.out.println("Thread is interrupted.. breaking from loop"); 
      return false; 
     }// ] 

     // [variant 2 - without sleep you get a busy wait which may load your cpu 
     //if (this.isInterrupted()) { 
     // System.out.println("Thread is interrupted.. breaking from loop"); 
     // return false; 
     //}// ] 
    } 
    return sin.hasNextLine(); 
} 
+0

Спасибо, я попробую. Но в любом случае это кажется неудобным, я не могу поверить, что нет более чистого способа. – dmitru

+0

Для 'System.in' я не нашел другого пути. Но учитывая, что это низкая производительность (чтение с консоли), это нормально для того, чтобы «спать». Кроме того, вы можете увеличить значение до 50 или 100, увидеть, влияет ли это на вашу работу. Полагаю, этого не произойдет. – Claudiu

-1

Мои испытания, похоже, не подтверждают ваши выводы. Он работает как ожидалось!

Я написал следующий демонстрационный код

public class DemoThread extends Thread { 

    Scanner sin = new Scanner(System.in); 

    @Override 
    public void run() { 
     while (sin.hasNextLine()) { 
      if(this.isInterrupted()) { 
       System.out.println("Thread is interrupted.. breaking from loop"); 
       break; 
      } 

      String message = sin.nextLine(); 
      System.out.println("Message us " + message); 

      // do processing... 
     } 
    } 

    public static void main(String args[]) throws InterruptedException { 

     DemoThread thread = new DemoThread(); 
     thread.start(); 
     Thread.sleep(5000); 
     thread.interrupt(); 

    } 

} 

и выход

a 
Message us a 
s 
Message us s 
asd 
Thread is interrupted.. breaking from loop 

Поэтому, пожалуйста, проверьте еще раз. Также, если вы запутались с выходом asd, это строка ввода из предыдущей итерации цикла, в точке которой нить не прерывалась. Если вы не хотите, что вы можете сделать

if(!this.isInterrupted()) { 
    String message = sin.nextLine(); 
} 

Why is this happening? 

Допустим, в итерационном поток не прерывается, так что войти в то время цикла (hasNext() проходит из-за строки чтения в предыдущем итерация). Он проверяет, прерывается ли поток (скажем, это не в данный момент времени) и переходит к следующей строке (сканирование новой строки из stdinput). Теперь можно сказать, что поток прерывается. Ваша программа будет ждать, пока вы введете какую-нибудь строку (для которой вы должны нажать enter в консоли). Таким образом, даже если поток является inetrrupted, строка будет считана, и эта строка будет использоваться для оценки операции hasNext() (которая будет оцениваться как истина), и контекст войдет в цикл while. Вот увидит, что поток прерывается и прерывается.

Чтобы избежать этого, вам нужно прочитать строку внутри if (! This.isInterrupted()). Обратитесь к моему коду выше.

+1

какой java/os вы используете? нить не прерывается, если вы не нажмете клавишу ввода на клавиатуре (для этого примера «System.in»). В принципе, вы бы хотели прервать его, не нажимая кнопку enter. – Claudiu

+1

Когда вы прерываете поток, все, что происходит, это то, что прерванный флаг устанавливается. Нить не выходит из метода hasNextLine раньше. – Joni

+0

to csoroiu: да, у меня такое же поведение – dmitru

-1

Обычно, если вы хотите иметь нить работает в течение неопределенного периода времени, но все еще быть в состоянии прервать его, вы могли бы сделать это следующим образом:

while (!Thread.currentThread().isInterrupted()) { 
    while (scanner.hasNextLine()) { 
    ... 
    } 
} 
+1

нить не прерывается, если вы не нажмете клавишу ввода на клавиатуре (при использовании System.in в качестве входа для сканера). В принципе, вы бы хотели прервать его, не нажимая кнопку enter. – Claudiu

0

Вы можете использовать логическое значение, а затем установить его в ложное, если вы хотите, чтобы остановить время цикла

sin = new Scanner(System.in); 
    boolean = runLoop = true; 
    while (sin.hasNextLine() && runLoop) { 
     if (this.isInterrupted()) 
     break; 

     message = sin.nextLine(); 

    // do processing...   
    } 
Смежные вопросы