3

我有一个线程可以读取用户输入并通过网络发送。线程位于这样的循环中:

sin = new Scanner(System.in);

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

    message = sin.nextLine();

    // do processing...        
}

但是当我尝试中断线程时,它不会退出该hasNextLine()方法。

我怎样才能真正退出这个循环?

4

4 回答 4

6

尝试用sin.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();
}
于 2013-10-02T06:38:40.983 回答
0

您可以使用布尔值,然后在要停止 while 循环时将其设置为 false

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

    message = sin.nextLine();

    // do processing...        
}
于 2013-10-02T07:04:50.370 回答
-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?

可以说在迭代中线程没有被中断,因此它进入了while循环(hasNext()由于先前迭代中读取的字符串而通过)。它检查线程是否被中断(可以说它不是在这个时间点)并继续到下一行(从标准输入扫描新字符串)。现在让我们说线程被中断。您的程序将等到您输入一些字符串(您必须在控制台中按 Enter 键)。因此,即使线程中断,也会读取字符串,并且该字符串将用于评估 hasNext() 操作(将评估为真),并且上下文将进入 while 循环。在这里它将看到线程被中断并中断。

为避免这种情况,您需要在 if(!this.isInterrupted()) 语句中读取字符串。请参阅我上面的代码。

于 2013-10-02T06:07:09.657 回答
-1

通常如果你想让一个线程无限期地运行,但仍然能够中断它,你会这样做:

while (!Thread.currentThread().isInterrupted()) {
  while (scanner.hasNextLine()) {
    ...
  }
}
于 2013-10-02T06:08:20.990 回答