If I would write:
int selectedChannels = selector.select(); Set selectedKeys = selector.selectedKeys(); if ( selectedChannels != selectedKeys.size() ) { // Selector.select() returned because of a call to Selector.wakeup() // so do synchronization. } // Continue with handling selected channels.
would it correctly detect the wakeup-call?
Backgroundinformation:
I'm writing a server which most of the time just receives packets and stores them in a file. Very rarely the application has the need to send itself a special packet. For this it initiates a connection (from a different thread) to the server socket:
SocketChannel channel = SocketChannel.open(); channel.configureBlocking( false ); channel.connect( new InetSocketAddress( InetAddress.getLocalHost(), PORT )); selector.wakeup(); SelectionKey key = channel.register( selector, SelectionKey.OP_CONNECT );
The problem is that SelectableChannel.register() might block if the main thread is already in Selector.select(). To prevent this from happening I'm calling Selector.wakeup() which let's the main thread return prematurely from select(). To make sure the other thread has the chance to complete the register-call, I would have to synchronize the main thread, but I would have to do it after every return from select(). If I could detect whether it returned from select() because of a wakeup() call, then I could optimize it for just this case.
So, in theory the top code snippet should work, but I was wondering whether it would only do so, because it relies on some unspecified behavior?
Thanks for any hints.
Best Answer
I would guess that the proposed snippet would not work at all in principle, per the contracts of
Selector#select()
andSelector#selectedKeys()
. From Selector:As I read that, the size of the
selectedKeys
set should always equal the number returned byselect
by definition. I have noticed - as you may have as well - that some implementations don't quite follow the documentation, and in factselectedKeys
returns all keys with updated ready-operation sets, even if they were not updated during a call toselect
. The only other indicator that the select woke up due to a call towakeup
might be that the number of keys is zero; however either method would be unreliable, at best.The usual way to handle this is, as implied, through concurrency control. I wouldn't worry about execution time here; this is a classic example of premature optimization.
Unless you're really worried about single digit microsecond tolerances, you won't notice any slowdown - and if you are worried about that level of tolerance, a
Selector
isn't going to be reliable enough for you anyway.Here's an example of the usual mechanism for this, using a
ReentrantLock
to accomplish the appropriate concurrency: