Чтение из InputStream - неблокирование с занятым ожиданием, блокировка VS с таймаутом? - PullRequest
0 голосов
/ 11 февраля 2019

Задача состоит в том, чтобы читать из 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);
            }
        }
    
    }
    

1 Ответ

0 голосов
/ 11 февраля 2019

Оба метода имеют недостатки.При использовании available() ваша программа может зависнуть навсегда в случае EOF.При отправке блокировки read() существует вероятность того, что фоновый вызов завершится и будет использовать данные из потока после истечения времени ожидания.Поэтому данные будут потеряны.

Когда ваш поток является потоком сокета, вы можете установить тайм-аут сокета и обработать SocketTimeoutException в своем коде.Современная Java также предоставляет асинхронный API для типов ввода / вывода без сокетов.Вы можете вызвать его методы, возвращающие Future.Однако, если вы решите отменить или отказаться от Future, канал может быть помечен как несогласованный и отказаться от дальнейшей работы.

Если это какой-то старый сторонний API, который возвращает черный ящик InputStream, вы можете использовать мою обертку, чтобы получитьповедение, подобное сокету.Во внутреннем буфере сохраняются байты, которые вы не используете: https://gist.github.com/basinilya/a5392de106cd890a28742960bcc5cf8c

...