Search code examples
javaniorace-condition

How to eliminate race condition in Rox NIO tutorial


I've been using this tutorial for a simple file transfer client/server using socket IO. I changed the response handler to accept multiple reads as a part of one file, as I will be dealing with large files, potentially up to 500 MB. The tutorial didn't account for large server responses, so I'm struggling a bit, and I've created a race condition.

Here's the response handler code:

public class RspHandler {

private byte[] rsp = null;
public synchronized boolean handleResponse(byte[] rsp) {
    this.rsp = rsp;
    this.notify();
    return true;
}

public synchronized void waitForResponse() {
    while(this.rsp == null) {
        try {
            this.wait();
        } catch (InterruptedException e) {
        }
    }
    System.out.println("Received Response : " + new String(this.rsp));
}

public synchronized void waitForFile(String filename) throws IOException {
    String filepath = "C:\\a\\received\\" + filename;
    FileOutputStream fos = new FileOutputStream(filepath);
    while(waitForFileChunk(fos) != -1){}
    fos.close();
}

private synchronized int waitForFileChunk(FileOutputStream fos) throws IOException
{
    while(this.rsp == null) {
        try {
            this.wait();
        } catch (InterruptedException e) {
        }
    }
    fos.write(this.rsp);
    int length = this.rsp.length;
    this.rsp = null;
    if(length < NioClient.READ_SIZE)//Probably a bad way to find the end of the file
    {
        return -1;
    }
    else
    {
        return length;
    }

}
}

The main thread of the program creates a RspHandler on the main thread, and passes it to a client, created on a separate thread. The main thread tells the client to request a file, then tells the RspHandler to listen for a response. When the client reads from the server(it reads in chunks of about 1KB right now), it calls the handleResponse(byte[] rsp) method, populating the rsp byte array.

Essentially, I'm not writing the received data to a file as fast as it comes. I'm a bit new to threads, so I'm not sure what to do to get rid of this race condition. Any hints?


Solution

  • this is classic consumer/producer. the most straightforward/easiest way to handle this is to use a BlockingQueue. producer calls put(), consumer calls take().

    note, using a BlockingQueue usually leads to the "how do i finish" problem. the best way to do that is to use the "poison pill" method, where the producer sticks a "special" value on the queue which signals to the consumer that there is no more data.