如何停止在 Java 中的阻塞读取操作中等待的线程?
Posted
技术标签:
【中文标题】如何停止在 Java 中的阻塞读取操作中等待的线程?【英文标题】:How to stop a thread waiting in a blocking read operation in Java? 【发布时间】:2011-05-10 02:38:32 【问题描述】:我有一个执行以下代码的线程:
public void run()
try
int n = 0;
byte[] buffer = new byte[4096];
while ((n = in.read(buffer)) != -1)
out.write(buffer, 0, n);
out.flush();
catch (IOException e)
System.out.println(e);
其中in
是System.in
。我怎样才能优雅地停止这样的线程?关闭 System.in
或使用 Thread.interrupt
似乎都不起作用。
【问题讨论】:
使用中断会发生什么? @tulskiy:线程继续运行,直到手动输入 Ctrl-D (EOF)。 【参考方案1】:这是因为读取 System.in (InputStream) 是一个阻塞操作。
看这里Is it possible to read from a InputStream with a timeout?
【讨论】:
谢谢。使用从System.in
中提取的NIO FileChannel
可以通过关闭System.in
来停止线程。关闭System.in
会导致AsynchronousCloseException
中断阻塞FileChannel.read
。【参考方案2】:
您偶然发现了一个 9 岁的 bug 没有人愿意修复。他们说this bug report 中有一些解决方法。很可能,您需要找到其他方法来设置超时(忙于等待似乎是不可避免的)。
【讨论】:
有趣的是,当我偶然发现这一点时,它的行为更加奇怪。中断有效,但花了 2.5 分钟! (ubuntu 18.04)【参考方案3】:你可以使用 available() 方法(它是非阻塞的)来检查是否有预先读取的内容。
在伪java中:
//...
while(running)
if(in.available() > 0)
n = in.read(buffer);
//do stuff with the buffer
else
Thread.sleep(500);
//when running set to false exit gracefully here...
【讨论】:
Abritraary number,如果你不睡觉,你最终会进入一个热循环,让 CPU 等待读取可用字节。我的假设是这个线程将花费大部分时间等待输入。 使用available
几乎可以解决问题。问题是如果 EOF available
返回 0 并且线程继续执行。 +1 补偿不公平 -1 =)
我只是想到了响应能力...... PeterMmms 链接说明了一切:***.com/questions/804951/…
谢谢!你的回答刚刚救了我的命!【参考方案4】:
在其他线程中关闭流是否安全?
这个对我有用。在这种情况下,in.read(...)
会抛出异常 SocketException
。
【讨论】:
【参考方案5】:如果您想给用户一些时间来输入数据 - 可能允许覆盖默认值或中断一些自动化过程 - 然后先等待并在暂停后检查可用输入:
System.out.println("Enter value+ENTER within 5 Seconds to override default value: ");
try
Thread.sleep(5000);
catch InterruptedException e)
try
int bytes = System.in.available();
if (bytes > 0)
System.out.println("Using user entered data ("+size+" bytes)");
else
System.out.println("Using default value");
catch(IOException e) /*handle*/
【讨论】:
【参考方案6】:我今天遇到了同样的问题,我就是这样解决的,使用in.ready()
:
public void run()
String line;
// Some code
while(!Thread.currentThread().isInterrupted())
try
if (in.ready())
line = in.readLine();
catch (Exception e)
try
Thread.currentThread().wait(500);
catch (InterruptedException e1)
// Do what we want when thread is interrupted
【讨论】:
很有趣,但是在没有什么可读取的情况下一直执行循环不是要占用大量 CPU 吗? 实际上这就是为什么我让线程每次迭代都等待一段时间。但你是对的,它没有它应该的那么有效。现在取决于软件的用途。 很确定如果流中没有换行符,这仍然会挂起。如果有单个字节, in.ready() 返回 true,in.readLine() 读取它,然后继续(永远)等待换行符。【参考方案7】:您可以为此使用外部标志
boolean flag = true;
public void run()
try
int n = 0;
byte[] buffer = new byte[4096];
while ((n = in.read(buffer)) != -1 && flag)
out.write(buffer, 0, n);
out.flush();
catch (IOException e)
System.out.println(e);
【讨论】:
这不会中断已经阻塞的调用,所以它不能解决问题。以上是关于如何停止在 Java 中的阻塞读取操作中等待的线程?的主要内容,如果未能解决你的问题,请参考以下文章
Springboot Java多线程操作本地文件,加读写锁,阻塞的线程等待运行中的线程执行完再查询并写入