시간 초과로 InputStream에서 읽을 수 있습니까?


147

특히, 문제는 다음과 같은 방법을 작성하는 것입니다.

int maybeRead(InputStream in, long timeout)

데이터가 'timeout'밀리 초 내에 사용 가능한 경우 반환 값은 in.read ()와 동일하고 그렇지 않으면 -2입니다. 메소드가 리턴되기 전에, 생성 된 모든 스레드가 종료되어야합니다.

인수를 피하기 위해 Sun (모든 Java 버전)이 문서화 한 주제는 java.io.InputStream입니다. 이것은 보이는 것처럼 간단하지 않습니다. 다음은 Sun의 설명서에서 직접 지원되는 몇 가지 사실입니다.

  1. in.read () 메소드는 인터럽트 할 수 없습니다.

  2. Reader 또는 InterruptibleChannel에서 InputStream을 래핑하는 것은 도움이되지 않습니다. 모든 클래스가 할 수있는 것은 InputStream의 메소드를 호출하는 것입니다. 해당 클래스를 사용할 수 있다면 InputStream에서 동일한 논리를 직접 실행하는 솔루션을 작성할 수 있습니다.

  3. in.available ()이 항상 0을 반환하는 것은 허용됩니다.

  4. in.close () 메소드는 차단하거나 아무 것도 할 수 없습니다.

  5. 다른 스레드를 죽이는 일반적인 방법은 없습니다.

답변:


83

inputStream.available () 사용

System.in.available ()이 항상 0을 반환하는 것은 허용됩니다.

나는 그 반대를 찾았습니다-항상 사용 가능한 바이트 수에 가장 적합한 값을 반환합니다. 에 대한 Javadoc InputStream.available():

Returns an estimate of the number of bytes that can be read (or skipped over) 
from this input stream without blocking by the next invocation of a method for 
this input stream.

타이밍 / 정말로 인해 추정치를 피할 수 없습니다. 새로운 데이터가 지속적으로 도착하기 때문에 수치는 과소 평가 될 수 있습니다. 그러나 항상 다음 통화에서 "캐치"합니다. 도착한 모든 데이터, 즉 새 통화 순간에 도착한 데이터를 고려해야합니다. 위의 조건에 데이터가 실패하면 영구적으로 0을 반환합니다.

첫 번째주의 사항 : InputStream의 구체적인 하위 클래스는 available ()을 담당합니다.

InputStream추상 클래스입니다. 데이터 소스가 없습니다. 사용 가능한 데이터를 갖는 것은 의미가 없습니다. 따라서 javadoc available()도 상태를 나타냅니다.

The available method for class InputStream always returns 0.

This method should be overridden by subclasses.

실제로 구체적인 입력 스트림 클래스는 available 0을 재정 의하여 상수 0이 아닌 의미있는 값을 제공합니다.

두 번째주의 사항 : Windows에서 입력을 입력 할 때 캐리지 리턴을 사용하십시오.

를 사용하는 경우 System.in명령 쉘이 넘겨 줄 때만 프로그램이 입력을받습니다. 파일 리디렉션 / 파이프를 사용하는 경우 (예 : somefile> java myJavaApp 또는 somecommand | java myJavaApp) 입력 데이터는 일반적으로 즉시 전달됩니다. 그러나 입력을 수동으로 입력하면 데이터 핸드 오버가 지연 될 수 있습니다. 예를 들어 Windows cmd.exe 셸을 사용하면 cmd.exe 셸 내에 데이터가 버퍼링됩니다. 캐리지 리턴 (control-m 또는 <enter>) 다음에 실행중인 Java 프로그램으로 만 데이터가 전달됩니다 . 그것은 실행 환경의 한계입니다. 물론, InputStream.available ()은 쉘이 데이터를 버퍼링하는 한 0을 반환합니다. 올바른 동작입니다. 해당 시점에 사용 가능한 데이터가 없습니다. 셸에서 데이터를 사용할 수있게되면이 메서드는 0보다 큰 값을 반환합니다. NB : Cygwin은 cmd를 사용합니다.

가장 간단한 솔루션 (차단 없음, 시간 초과 필요 없음)

이것을 사용하십시오 :

    byte[] inputData = new byte[1024];
    int result = is.read(inputData, 0, is.available());  
    // result will indicate number of bytes read; -1 for EOF with no data read.

또는 동등하게

    BufferedReader br = new BufferedReader(new InputStreamReader(System.in, Charset.forName("ISO-8859-1")),1024);
    // ...
         // inside some iteration / processing logic:
         if (br.ready()) {
             int readCount = br.read(inputData, bufferOffset, inputData.length-bufferOffset);
         }

보다 풍부한 솔루션 (시간 초과 기간 내에 버퍼를 최대로 채움)

이것을 선언하십시오 :

public static int readInputStreamWithTimeout(InputStream is, byte[] b, int timeoutMillis)
     throws IOException  {
     int bufferOffset = 0;
     long maxTimeMillis = System.currentTimeMillis() + timeoutMillis;
     while (System.currentTimeMillis() < maxTimeMillis && bufferOffset < b.length) {
         int readLength = java.lang.Math.min(is.available(),b.length-bufferOffset);
         // can alternatively use bufferedReader, guarded by isReady():
         int readResult = is.read(b, bufferOffset, readLength);
         if (readResult == -1) break;
         bufferOffset += readResult;
     }
     return bufferOffset;
 }

그런 다음 이것을 사용하십시오 :

    byte[] inputData = new byte[1024];
    int readCount = readInputStreamWithTimeout(System.in, inputData, 6000);  // 6 second timeout
    // readCount will indicate number of bytes read; -1 for EOF with no data read.

1
경우 is.available() > 1024이 제안은 실패합니다. 0을 반환하는 스트림이 있습니다. 예를 들어 최근까지 SSLSockets. 당신은 이것에 의존 할 수 없습니다.
Lorne의 후작

'is.available ()> 1024'사례는 특히 readLength를 통해 처리됩니다.
Glen Best

SSLSocket의 설명이 잘못되었습니다. 버퍼에 데이터가없는 경우 사용 가능한 경우 0을 반환합니다. 내 대답에 따라. Javadoc : "소켓에 버퍼링 된 바이트가없고 close를 사용하여 소켓이 닫히지 않으면 available는 0을 반환합니다."
Glen Best

@GlenBest 내 의견 re SSLSocket이 올바르지 않습니다. 최근까지 [내 강조]는 항상 0을 반환하는 데 사용되었습니다. 당신은 현재에 대해 이야기하고 있습니다. JSSE의 전체 역사에 대해 이야기하고 있으며 2002 년 Java 1.4에 처음 포함되기 전부터 협력 해 왔습니다 .
Lorne의 후작

while 루프 조건을 "while (is.available ()> 0 && System.currentTimeMillis () <maxTimeMillis && bufferOffset <b.length) {"로 변경하면 많은 CPU 오버 헤드가 절약되었습니다.
Logic1

65

스트림이 소켓에 의해 지원되지 않기 때문에 (사용할 수 없음 Socket.setSoTimeout())이 유형의 문제를 해결하는 표준 방법은 미래를 사용하는 것입니다.

다음 실행기와 스트림이 있다고 가정하십시오.

    ExecutorService executor = Executors.newFixedThreadPool(2);
    final PipedOutputStream outputStream = new PipedOutputStream();
    final PipedInputStream inputStream = new PipedInputStream(outputStream);

필자는 일부 데이터를 쓴 다음 마지막 데이터를 쓰고 스트림을 닫기 전에 5 초 동안 기다리는 작성자가 있습니다.

    Runnable writeTask = new Runnable() {
        @Override
        public void run() {
            try {
                outputStream.write(1);
                outputStream.write(2);
                Thread.sleep(5000);
                outputStream.write(3);
                outputStream.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    };
    executor.submit(writeTask);

이것을 읽는 일반적인 방법은 다음과 같습니다. 읽기는 데이터에 대해 무기한 차단되므로 5 초 안에 완료됩니다.

    long start = currentTimeMillis();
    int readByte = 1;
    // Read data without timeout
    while (readByte >= 0) {
        readByte = inputStream.read();
        if (readByte >= 0)
            System.out.println("Read: " + readByte);
    }
    System.out.println("Complete in " + (currentTimeMillis() - start) + "ms");

어떤 출력 :

Read: 1
Read: 2
Read: 3
Complete in 5001ms

작가가 응답하지 않는 것처럼보다 근본적인 문제가 있었다면 독자는 영원히 차단했을 것입니다. 나중에 읽기를 래핑하면 다음과 같이 시간 초과를 제어 할 수 있습니다.

    int readByte = 1;
    // Read data with timeout
    Callable<Integer> readTask = new Callable<Integer>() {
        @Override
        public Integer call() throws Exception {
            return inputStream.read();
        }
    };
    while (readByte >= 0) {
        Future<Integer> future = executor.submit(readTask);
        readByte = future.get(1000, TimeUnit.MILLISECONDS);
        if (readByte >= 0)
            System.out.println("Read: " + readByte);
    }

어떤 출력 :

Read: 1
Read: 2
Exception in thread "main" java.util.concurrent.TimeoutException
    at java.util.concurrent.FutureTask$Sync.innerGet(FutureTask.java:228)
    at java.util.concurrent.FutureTask.get(FutureTask.java:91)
    at test.InputStreamWithTimeoutTest.main(InputStreamWithTimeoutTest.java:74)

TimeoutException을 포착하고 원하는 정리 작업을 수행 할 수 있습니다.


14
그러나 차단 스레드는 어떻습니까?! 응용 프로그램이 종료 될 때까지 메모리에 남아 있습니까? 내가 맞으면 응용 프로그램에 많은 양의 스레드가 생성되어 응용 프로그램에 과부하가 걸리고 더 많은 스레드가 스레드를 차지하고 차단 된 풀을 사용하지 못하게 차단 할 수 있습니다. 내가 틀렸다면 정정 해주세요. 감사합니다.
Muhammad Gelbana

4
Muhammad Gelbana, 당신 말이 맞습니다 : 블로킹 read () 스레드가 계속 실행 중이며 괜찮습니다. 나는 이것을 막을 수있는 방법을 찾았습니다 : 시간 초과가 발생하면 호출 스레드에서 입력 스트림을 닫습니다 (제 경우에는 입력 스트림이 오는 안드로이드 블루투스 소켓을 닫습니다). 그렇게하면 read () 호출이 즉시 반환됩니다. 제 경우에는 int read (byte []) 오버로드를 사용하고 즉시 반환합니다. 어쩌면 int read () 오버로드가 IOException을 throw 할 것입니다.
Emmanuel Touzery

5
스레드 읽기가 애플리케이션이 종료 될 때까지 차단 된 상태로 유지되면 -1입니다.
Ortwin Angermeier

11
@ortang "TimeoutException을 잡아서 정리하면됩니다"라는 의미입니다. 예를 들어, 읽기 스레드를 종료하고 싶을 수 있습니다. ... catch (TimeoutException e) {executor.shutdownNow (); }
Ian Jones

12
executer.shutdownNow스레드를 죽이지 않습니다. 영향을 미치지 않고 중단하려고 시도합니다. 정리할 수 없으며 이는 심각한 문제입니다.
Marko Topolnik

22

InputStream이 Socket에 의해 지원되는 경우 setSoTimeout을 사용하여 소켓 제한 시간 (밀리 초)을 설정할 수 있습니다 . read () 호출이 지정된 시간 초과 내에 차단 해제되지 않으면 SocketTimeoutException이 발생합니다.

read () 호출하기 전에 소켓에서 setSoTimeout을 호출해야합니다.


18

나는 맹목적으로 받아들이 기보다는 문제 진술에 의문을 제기 할 것이다. 콘솔 또는 네트워크를 통한 시간 초과 만 필요합니다. 후자를 가지고 Socket.setSoTimeout()있고 HttpURLConnection.setReadTimeout()둘 다 정확히 필요한 것을 수행하는 경우, 구성 / 획득 할 때 올바르게 설정하기 만하면됩니다. 입력 스트림이 디자인이 좋지 않은 경우 응용 프로그램에서 나중에 임의의 지점으로두면 디자인이 매우 어색합니다.


10
읽기가 잠재적으로 상당한 시간 동안 차단 될 수있는 다른 상황이 있습니다. 예를 들어 테이프 드라이브, 원격으로 장착 된 네트워크 드라이브 또는 백엔드에 테이프 로봇이있는 HFS에서 읽을 때. (그러나 당신의 대답의 주요 추력은 맞습니다.)
Stephen C

1
귀하의 의견과 예를 들어 @StephenC +1. 더 많은 예제를 추가하기 위해 간단한 경우 소켓 연결이 올바르게 설정되었지만 DB에서 데이터를 가져와야하지만 읽기가 시도되지 않았지만 어떻게 든 발생하지 않았습니다 (DB가 응답하지 않고 쿼리가 진행되었다고 말할 수 있음) 잠금 상태). 이 시나리오에서는 소켓에서 읽기 작업을 명시 적으로 시간 초과하는 방법이 필요합니다.
sactiw

1
InputStream 추상화의 요점은 기본 구현에 대해 생각하지 않는 것입니다. 게시 된 답변의 장단점에 대해 논쟁하는 것이 공정합니다. 그러나 문제 진술에 의문을 제기하는 것은이 논의를 돕지 않을 것입니다.
pellucide

2
InputStream은 스트림에서 작동하며 차단되지만 시간 초과 메커니즘을 제공하지는 않습니다. 따라서 InputStream 추상화는 적절하게 설계된 추상화가 아닙니다. 따라서 스트림에서 타임 아웃하는 방법을 요구하는 것은별로 요구하지 않습니다. 따라서 문제는 매우 실용적인 문제에 대한 해결책을 요구하는 것입니다. 기본 구현 대부분이 차단됩니다. 이것이 바로 스트림의 본질입니다. 스트림의 다른쪽에 새로운 데이터가 준비되지 않으면 소켓, 파일, 파이프가 차단됩니다.
pellucide

2
@EJP. 어떻게했는지 모르겠어요 나는 당신에 동의하지 않았습니다. "InputStream에서 시간 초과하는 방법"이라는 문제 설명이 유효합니다. 프레임 워크는 시간 종료 방법을 제공하지 않으므로 그러한 질문을하는 것이 적절합니다.
pellucide 2016 년

7

Java NIO 패키지의 클래스를 사용하지 않았지만 여기에 도움이 될 것 같습니다 . 특히 java.nio.channels.Channelsjava.nio.channels.InterruptibleChannel 입니다.


2
+1 : OP가 InputStream만으로 요구하는 것을 신뢰할 수있는 방법이 있다고 생각하지 않습니다. 그러나 nio는 이러한 목적으로 무엇보다도 만들어졌습니다.
Eddie

2
OP는 기본적으로 이것을 배제했습니다. InputStreams는 본질적으로 블로킹되며 인터럽트 불가능할 수 있습니다.
Lorne의 후작

5

다음은 System.in에서 NIO FileChannel을 가져오고 타임 아웃을 사용하여 데이터의 가용성을 확인하는 방법입니다. 이는 질문에 설명 된 문제의 특별한 경우입니다. 콘솔에서 실행하고 입력을 입력하지 말고 결과를 기다리십시오. Windows 및 Linux의 Java 6에서 성공적으로 테스트되었습니다.

import java.io.FileInputStream;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedByInterruptException;

public class Main {

    static final ByteBuffer buf = ByteBuffer.allocate(4096);

    public static void main(String[] args) {

        long timeout = 1000 * 5;

        try {
            InputStream in = extract(System.in);
            if (! (in instanceof FileInputStream))
                throw new RuntimeException(
                        "Could not extract a FileInputStream from STDIN.");

            try {
                int ret = maybeAvailable((FileInputStream)in, timeout);
                System.out.println(
                        Integer.toString(ret) + " bytes were read.");

            } finally {
                in.close();
            }

        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }

    /* unravels all layers of FilterInputStream wrappers to get to the
     * core InputStream
     */
    public static InputStream extract(InputStream in)
            throws NoSuchFieldException, IllegalAccessException {

        Field f = FilterInputStream.class.getDeclaredField("in");
        f.setAccessible(true);

        while( in instanceof FilterInputStream )
            in = (InputStream)f.get((FilterInputStream)in);

        return in;
    }

    /* Returns the number of bytes which could be read from the stream,
     * timing out after the specified number of milliseconds.
     * Returns 0 on timeout (because no bytes could be read)
     * and -1 for end of stream.
     */
    public static int maybeAvailable(final FileInputStream in, long timeout)
            throws IOException, InterruptedException {

        final int[] dataReady = {0};
        final IOException[] maybeException = {null};
        final Thread reader = new Thread() {
            public void run() {                
                try {
                    dataReady[0] = in.getChannel().read(buf);
                } catch (ClosedByInterruptException e) {
                    System.err.println("Reader interrupted.");
                } catch (IOException e) {
                    maybeException[0] = e;
                }
            }
        };

        Thread interruptor = new Thread() {
            public void run() {
                reader.interrupt();
            }
        };

        reader.start();
        for(;;) {

            reader.join(timeout);
            if (!reader.isAlive())
                break;

            interruptor.start();
            interruptor.join(1000);
            reader.join(1000);
            if (!reader.isAlive())
                break;

            System.err.println("We're hung");
            System.exit(1);
        }

        if ( maybeException[0] != null )
            throw maybeException[0];

        return dataReady[0];
    }
}

흥미롭게도 콘솔이 아닌 NetBeans 6.5에서 프로그램을 실행할 때 시간 초과가 전혀 작동하지 않으며 실제로 좀비 스레드를 종료하려면 System.exit () 호출이 필요합니다. 리더 .interrupt () 호출시 인터럽트 스레드 스레드 (!)가 발생합니다. 다른 테스트 프로그램 (여기에 표시되지 않음)은 채널을 닫으려고 시도하지만 작동하지 않습니다.


JDK 1.6이나 JDK 1.7에서는 Mac OS에서 작동하지 않습니다. 읽기 도중에 return을 누른 후에 만 ​​인터럽트가 인식됩니다.
Mostowski Collapse

4

jt가 말했듯이 NIO는 최고의 (올바른) 솔루션입니다. 그래도 실제로 InputStream에 갇혀 있다면

  1. 독점 작업 인 스레드를 생성하면 InputStream에서 읽고 결과를 버퍼에 넣어 버퍼를 원래 스레드에서 읽을 수 있습니다. 스트림 인스턴스가 하나만있는 경우에는 잘 작동합니다. 그렇지 않으면 Thread 클래스에서 사용되지 않는 메서드를 사용하여 스레드를 종료 할 수 있지만 리소스 누수가 발생할 수 있습니다.

  2. isAvailable을 사용하여 차단하지 않고 읽을 수있는 데이터를 나타냅니다. 그러나 (소켓과 같은) 경우에 따라 isAvailable이 0 이외의 다른 것을보고하기 위해서는 잠재적으로 블로킹 읽기가 필요할 수 있습니다.


5
Socket.setSoTimeout()똑같이 정확하고 훨씬 간단한 솔루션입니다. 또는 HttpURLConnection.setReadTimeout().
Lorne의 후작

3
@EJP-특정 상황에서는 "동일하게"정확합니다. 예를 들어 입력 스트림이 소켓 스트림 / HTTP 연결 스트림 인 경우.
Stephen C

1
@Stephen C NIO는 비 차단 기능이며 동일한 환경에서 선택할 수 있습니다. 예를 들어 비 차단 파일 I / O는 없습니다.
Lorne의 후작

2
@EJP하지만 (로컬 디스크에) 비 차단 파이프 IO (System.in), 파일 I / O를 비 블로킹있다 말도 안돼
woky

1
@EJP 대부분의 Unices System.in은 실제로 파이프 (쉘을 파일로 바꾸라고 명령하지 않은 경우)이며 파이프로서 비 블로킹 일 수 있습니다.
woky

0

이 답변 에서 영감을 얻어 조금 더 객체 지향 솔루션을 찾았습니다.

문자를 읽으려는 경우에만 유효합니다

BufferedReader를 재정의하고 다음과 같이 구현할 수 있습니다.

public class SafeBufferedReader extends BufferedReader{

    private long millisTimeout;

    ( . . . )

    @Override
    public int read(char[] cbuf, int off, int len) throws IOException {
        try {
            waitReady();
        } catch(IllegalThreadStateException e) {
            return 0;
        }
        return super.read(cbuf, off, len);
    }

    protected void waitReady() throws IllegalThreadStateException, IOException {
        if(ready()) return;
        long timeout = System.currentTimeMillis() + millisTimeout;
        while(System.currentTimeMillis() < timeout) {
            if(ready()) return;
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                break; // Should restore flag
            }
        }
        if(ready()) return; // Just in case.
        throw new IllegalThreadStateException("Read timed out");
    }
}

다음은 거의 완전한 예입니다.

일부 메소드에서 0을 반환합니다. 필요에 맞게 -2로 변경해야하지만 BufferedReader 계약에 0이 더 적합하다고 생각합니다. 아무 일도 일어나지 않았습니다. 단지 0자를 읽었습니다. readLine 메소드는 끔찍한 성능 킬러입니다. 실제로 readLin을 사용하려면 완전히 새로운 BufferedReader를 작성해야합니다. e . 지금은 스레드 안전하지 않습니다. readLines가 회선을 기다리는 동안 누군가 작업을 호출하면 예기치 않은 결과가 발생합니다.

나는 내가있는 곳 -2를 반환하는 것을 좋아하지 않습니다. EOS를 고려하기 위해 int <0인지 확인하는 사람들이 있기 때문에 예외가 발생합니다. 어쨌든, 이러한 메소드는 "차단할 수 없다"고 주장하며, 그 진술이 실제로 참이고 그냥 무시하지 않는지 확인해야합니다.

import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;
import java.nio.CharBuffer;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;

/**
 * 
 * readLine
 * 
 * @author Dario
 *
 */
public class SafeBufferedReader extends BufferedReader{

    private long millisTimeout;

    private long millisInterval = 100;

    private int lookAheadLine;

    public SafeBufferedReader(Reader in, int sz, long millisTimeout) {
        super(in, sz);
        this.millisTimeout = millisTimeout;
    }

    public SafeBufferedReader(Reader in, long millisTimeout) {
        super(in);
        this.millisTimeout = millisTimeout;
    }



    /**
     * This is probably going to kill readLine performance. You should study BufferedReader and completly override the method.
     * 
     * It should mark the position, then perform its normal operation in a nonblocking way, and if it reaches the timeout then reset position and throw IllegalThreadStateException
     * 
     */
    @Override
    public String readLine() throws IOException {
        try {
            waitReadyLine();
        } catch(IllegalThreadStateException e) {
            //return null; //Null usually means EOS here, so we can't.
            throw e;
        }
        return super.readLine();
    }

    @Override
    public int read() throws IOException {
        try {
            waitReady();
        } catch(IllegalThreadStateException e) {
            return -2; // I'd throw a runtime here, as some people may just be checking if int < 0 to consider EOS
        }
        return super.read();
    }

    @Override
    public int read(char[] cbuf) throws IOException {
        try {
            waitReady();
        } catch(IllegalThreadStateException e) {
            return -2;  // I'd throw a runtime here, as some people may just be checking if int < 0 to consider EOS
        }
        return super.read(cbuf);
    }

    @Override
    public int read(char[] cbuf, int off, int len) throws IOException {
        try {
            waitReady();
        } catch(IllegalThreadStateException e) {
            return 0;
        }
        return super.read(cbuf, off, len);
    }

    @Override
    public int read(CharBuffer target) throws IOException {
        try {
            waitReady();
        } catch(IllegalThreadStateException e) {
            return 0;
        }
        return super.read(target);
    }

    @Override
    public void mark(int readAheadLimit) throws IOException {
        super.mark(readAheadLimit);
    }

    @Override
    public Stream<String> lines() {
        return super.lines();
    }

    @Override
    public void reset() throws IOException {
        super.reset();
    }

    @Override
    public long skip(long n) throws IOException {
        return super.skip(n);
    }

    public long getMillisTimeout() {
        return millisTimeout;
    }

    public void setMillisTimeout(long millisTimeout) {
        this.millisTimeout = millisTimeout;
    }

    public void setTimeout(long timeout, TimeUnit unit) {
        this.millisTimeout = TimeUnit.MILLISECONDS.convert(timeout, unit);
    }

    public long getMillisInterval() {
        return millisInterval;
    }

    public void setMillisInterval(long millisInterval) {
        this.millisInterval = millisInterval;
    }

    public void setInterval(long time, TimeUnit unit) {
        this.millisInterval = TimeUnit.MILLISECONDS.convert(time, unit);
    }

    /**
     * This is actually forcing us to read the buffer twice in order to determine a line is actually ready.
     * 
     * @throws IllegalThreadStateException
     * @throws IOException
     */
    protected void waitReadyLine() throws IllegalThreadStateException, IOException {
        long timeout = System.currentTimeMillis() + millisTimeout;
        waitReady();

        super.mark(lookAheadLine);
        try {
            while(System.currentTimeMillis() < timeout) {
                while(ready()) {
                    int charInt = super.read();
                    if(charInt==-1) return; // EOS reached
                    char character = (char) charInt;
                    if(character == '\n' || character == '\r' ) return;
                }
                try {
                    Thread.sleep(millisInterval);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt(); // Restore flag
                    break;
                }
            }
        } finally {
            super.reset();
        }
        throw new IllegalThreadStateException("readLine timed out");

    }

    protected void waitReady() throws IllegalThreadStateException, IOException {
        if(ready()) return;
        long timeout = System.currentTimeMillis() + millisTimeout;
        while(System.currentTimeMillis() < timeout) {
            if(ready()) return;
            try {
                Thread.sleep(millisInterval);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt(); // Restore flag
                break;
            }
        }
        if(ready()) return; // Just in case.
        throw new IllegalThreadStateException("read timed out");
    }

}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.