Wednesday, March 20, 2013

Reactor Pattern Explained - Part 3

This is the 3rd and final post of the topic Reactor Pattern Explained. If you haven't read the previous posts, please read them since they include a great deal of explanations.

Reacter Pattern Explained - Part 1
Reacter Pattern Explained - Part 2

In this post the usage of Thread pools in Handlers is explained. We will create an extended version of Handler class named HandlerWithThreadPool. Check this out.


public class HandlerWithThreadPool extends Handler {

    static ExecutorService pool = Executors.newFixedThreadPool(2);
    static final int PROCESSING = 2;

    public HandlerWithThreadPool(Selector sel, SocketChannel c) throws IOException {
        super(sel, c);
    }

    void read() throws IOException {
        int readCount = socketChannel.read(input);
        if (readCount > 0) {
            state = PROCESSING;
            pool.execute(new Processer(readCount));
        }
        //We are interested in writing back to the client soon after read processing is done.
        selectionKey.interestOps(SelectionKey.OP_WRITE);
    }

    //Start processing in a new Processer Thread and Hand off to the reactor thread.
    synchronized void processAndHandOff(int readCount) {
        readProcess(readCount);
        //Read processing done. Now the server is ready to send a message to the client.
        state = SENDING;
    }

    class Processer implements Runnable {
        int readCount;
        Processer(int readCount) {
            this.readCount =  readCount;
        }
        public void run() {
            processAndHandOff(readCount);
        }
    }
}

Notice that there is a new state PROCESSING introduced and that the read() method is over-ridden. Now when a Read Event is dispatched to this Handler, it will read the data but not change the state to SENDING. It will create a Processer which will process the message and run it in a different Thread in the Thread pool and set the Interested Operation to OP_WRITE. At this point even if the Channel is ready to be written to and the Hander is interested in writing, the Handler will not write since its still in PROCESSING state. See the run() method of the Handler, it will only write when its in SENDING state. Once the Processer is done with its read process, it will change the state to SENDING. Now the Handler can send data to the client.

Lets run the Reactor with the boolean isWithThreadPool set to true.

public static void main(String[] args) throws IOException{

    Reactor reactor  = new Reactor(9900, true);
    new Thread(reactor).start();
}

Notice that the size of the Thread pool is 2 which would limit the number of Handlers to run concurrently to 2. As we already know, when the events are handled concurrenly we can easyly improve the system performance.

Done :). Hope you find this useful. Have fun with coding.
Cheers.