Search code examples
javahttpurlconnectionbufferedinputstream

How to avoid starving BufferedInputStream?


I read data from a source location via BufferedInputStream and I pass the data to a destination using BufferedOutputStream. The problem I'm having is that sometimes my thread never exits the while loop because of starving on the bandwidth. Any ideas? Here's the code:

BufferedInputStream bis = new BufferedInputStream(sourceConnection.getInputStream());
BufferedOutputStream request = new BufferedOutputStream(destConnection.getOutputStream());
request.write(content.getBytes("UTF-8"));
boolean eof = false;
byte[] input = new byte[4096];
while ((length = bis.read(input)) != -1) {
    request.write(input, 0, length);
    request.flush();
}
request.close();
bis.close();

Solution

  • So to fix the issue I did a few things. I set the entire transfer process in a separate thread using an executor with a timeout

    ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
    final Future<Boolean> handler = executor.submit(new Callable<Boolean>() {
        @Override
        public Boolean call() throws Exception {
            return processTransfer();
        }
    });
    success = handler.get(10, TimeUnit.MINUTES);
    

    That way if the transfer takes longer than 10 minutes, it exits with an exeption. The second thing was change the original code to detect starvation:

    long lastDataRecvTime = System.currentTimeMillis();
    byte[] input;
    while (true) {
        if(System.currentTimeMillis() - lastDataRecvTime >= 5 * 60 * 1000) {
            throw new RuntimeException("Nothing received for 5 minutes. Transfer starved. Exiting");
        }
        int availableBuf = request.getAvailableBufferSize();
        if(availableBuf == 0) {
            request.flush();
            continue;
        }
        input = new byte[Math.min(4096, availableBuf)];
        int length = bis.read(input);
        if (length == -1)
            break;
    
        if(length == 0) {
            try { Thread.sleep(1); } catch (Exception ignored){}
            continue;
        }
    
        lastDataRecvTime = System.currentTimeMillis();
        request.write(input, 0, length);
    }
    request.flush();
    request.close();
    bis.close();
    

    Thanks for the help