【问题标题】:Reading from InputStream - non-blocking with busy waiting VS blocking with timeout?从 InputStream 读取 - 忙等待时的非阻塞 VS 超时阻塞?
【发布时间】:2019-02-11 16:36:38
【问题描述】:

任务是从 InputStream 中读取数据并在可配置的时间内等待结果。

给定两种选择,哪一种更可取?或者建议另一个。

  1. 阻止对 read() 方法的调用,您必须自己超时
  2. 对 available() 的非阻塞调用,您必须使用忙等待和睡眠来轮询它

    import java.io.IOException;
    import java.io.InputStream;
    import java.util.concurrent.*;
    
    public class MyClass {
    
        public static void main(String[] args) throws InterruptedException, ExecutionException, IOException {
            MyClass myClass = new MyClass();
            final InputStream in = System.in;
            final long timeout = 1000;
    
            final int result = myClass.blockingWithTimeout(in, timeout);
            //  final int result = myClass.nonBlockingBusyWait(in, timeout);
    
            System.out.println("Result " + result);
        }
    
        public int nonBlockingBusyWait(final InputStream is, long timeoutMs) throws IOException, InterruptedException {
            final long start = System.currentTimeMillis();
            while (is.available() == 0 && (System.currentTimeMillis() < start + timeoutMs)) {
                Thread.sleep(1);
            }
            if (is.available() == 0) {
                return -1;
            } else {
                return is.read();
            }
        }
    
        public int blockingWithTimeout(final InputStream is, long timeoutMs) throws InterruptedException, ExecutionException {
            ExecutorService es = Executors.newSingleThreadExecutor();
            Future<Integer> future = es.submit((Callable<Integer>) is::read);
            try {
                return future.get(timeoutMs, TimeUnit.MILLISECONDS);
    
            } catch (TimeoutException e) {
                return -1;
            } catch (InterruptedException | ExecutionException e) {
                throw e;
            } finally {
                future.cancel(true);
            }
        }
    
    }
    

【问题讨论】:

  • 不要使用available()。在 EOF 的情况下,这是标准未指定的行为
  • 永远不要比较currentTimeMillis()。总是减去最后期限并与零进行比较。

标签: java inputstream blocking nonblocking


【解决方案1】:

这两种方法都有缺陷。当使用 available() 时,您的程序可能会在 EOF 的情况下永远挂起。提交阻塞read() 时,后台调用有可能在超时后 完成并使用流中的数据。因此数据会丢失。

当您的流是套接字流时,您可以设置套接字超时并在代码中处理SocketTimeoutException。现代 Java 还为非套接字 I/O 类型提供异步 API。你可以调用它的方法返回Future。但是,如果您决定取消或放弃 Future,该频道可能会被标记为不一致并拒绝进一步操作。

如果是一些旧的 3rd-party API 返回一个黑盒 InputStream,你可以使用我的包装器来获得类似套接字的行为。它节省了您在内部缓冲区中不使用的字节:https://gist.github.com/basinilya/a5392de106cd890a28742960bcc5cf8c

【讨论】:

    猜你喜欢
    • 2015-01-15
    • 2013-01-05
    • 2010-10-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多