views:

225

answers:

2

hello,

i'm working with java.nio.channels.Selector and i'd like to create a separate thread for each selectedKey that is ready for read/write/accept but i want to make sure that the same socket is never handled by two different threads simultaneously. what would be the best way to do it ? i was thinking to cancel each selectedKey before creating the thread that'll handle it's socket and re-registering the socket to the selector once the thread has finished it's life but i/m not sure how efficient this will be....

+1  A: 

I think creating a separate thread for each socket could end up being too many. Also, creating a new Thread is kind of expensive in execution time. You should cap the number of active threads and limit new thread creation by using a thread pool. java.util.concurrent.Executors offers the ability to create a fixed thread pool. Details in http://java.sun.com/docs/books/tutorial/essential/concurrency/pools.html .

If it's sockets you want to protect from being hit by multiple threads at one time, I'd consider the very simplest exclusion: Locking on the socket object. There could be more efficient strategies but probably none simpler or more foolproof.

Update

If another selection is done while some of the earlier returned sockets are still in processing, you could end up with threads interfering with each other. Shutting other threads out via locking is possible but not really an elegant solution (sorry).

Two alternatives I can think of:

  • deregister the channel before starting your processing thread on it, and re-register it at the end of the processing activity. Sounds klutzy but should get the job done.

  • maintain your own data structure of in-progress channels, e.g. a Set, and add a newly found-ready channel to that set before giving it to a thread, and remove it before returning from the thread. When processing channels from the selection set, ignore any that are already in the set. All use of this set will need to be synchronized.

Carl Smotricz
hi, thank for your reply.i am using a thread pool.my problem is that a socket is still registered to the Selector while still being handled by a thread from the pool.this might cause the unnecessary creation of a new task for the thread pool which will wait for the release of the socket only to find out that the necessary work has already been done.it's the creation of the second task that i'm trying to prevent.
yuri
Sorry to be so slow to catch on. I've updated my answer with more suggestions.
Carl Smotricz
+2  A: 

There's a really good Doug Lea presentation about Scaleable I/O in Java, which I followed when building my server. I take the following approach:

I have a single I/O thread within my "reactor" that only performs I/O (and very basic decoding / encoding); It simply translates between bytes and message objects and then passes off incoming message objects to a thread pool for business logic processing. I would highly recommend this approach - Unless your I/O thread becomes saturated there is no need for more than one I/O thread, and I would imagine most I/O bottlenecks are because other processing it taking place on this thread.

If you can prove your I/O thread is saturated you could follow the "multiple reactor" pattern suggested in the presentation whereby a master reactor accepts incoming connections and then hands them off to child reactors that perform the procesing. Each child reactor multiplexes between a subset of the total connections, and hence there's no danger of more than one thread interacting with a given SelectionKey.

Adamski
My first reaction was to recommend this too. I wasn't sure, though, if some of these read/write/accept operations wouldn't incur some delay in spite of being "ready". But if Doug Lea recommends this too, it's probably a good way to do things.
Carl Smotricz