Java 从InputStream读取-忙等待时无阻塞与超时时阻塞?

Java 从InputStream读取-忙等待时无阻塞与超时时阻塞?,java,inputstream,blocking,nonblocking,Java,Inputstream,Blocking,Nonblocking,任务是从InputStream读取数据,并在可配置的时间内等待结果 有两种选择,哪一种更可取?或者建议另一个 阻止对read()方法的调用,您必须自己超时 对available()的非阻塞调用,您必须使用忙等待和睡眠来轮询该调用 import java.io.IOException; import java.io.InputStream; import java.util.concurrent.*; public class MyClass { public static void

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

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

  • 阻止对read()方法的调用,您必须自己超时
  • 对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);
            }
        }
    
    }
    
    import java.io.IOException;
    导入java.io.InputStream;
    导入java.util.concurrent.*;
    公共类MyClass{
    公共静态void main(字符串[]args)引发InterruptedException、ExecutionException、IOException{
    MyClass MyClass=新的MyClass();
    最终输入流输入=System.in;
    最终长超时=1000;
    最终int结果=myClass.blockingWithTimeout(in,timeout);
    //最终int结果=myClass.nonBlockingBusyWait(in,超时);
    系统输出打印项次(“结果”+结果);
    }
    public int nonBlockingBusyWait(最终输入流为,long-timeoutMs)抛出IOException、InterruptedException{
    最终长启动=System.currentTimeMillis();
    而(is.available()==0&&(System.currentTimeMillis()

  • 这两种方法都有缺陷。使用
    available()
    时,如果发生EOF,程序可能会永久挂起。提交阻塞
    read()
    时,后台调用有可能在超时后完成并使用流中的数据。因此,数据将丢失

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


    如果是某个旧的第三方API返回blackbox InputStream,您可以使用我的包装器获得类似套接字的行为。它会将不使用的字节保存在内部缓冲区中:

    不要使用
    available()
    。在EOFDon的情况下,这是标准未指定的行为。我永远不会比较
    currentTimeMillis()
    。始终减去截止日期并与零进行比较。