NIO selector: how to register a new channel when choosing

I have subclasses of Thread with a private Selector and a public register(SelectableChannel channel, ...) method register(SelectableChannel channel, ...) that allows other threads to register channels for the selector.

As said here , the register() channel is blocked during the select() / select(long timeout) wakeup() selector, so we need a wakeup() selector.

My thread is selected indefinitely (unless it is interrupted), and it really manages to get into the next choice before calling the register() channel. So I thought that I was using a simple lock with synchronized blocks to ensure that register() would happen first.

Code: (unnecessary code deleted for reading)

 public class SelectorThread extends Thread { ... public void register(SelectableChannel channel, Attachment attachment) throws IOException { channel.configureBlocking(false); synchronized (this) { // LOCKING OCCURS HERE selector.wakeup(); channel.register(selector, SelectionKey.OP_READ, attachment); } } @Override public void run() { int ready; Set<SelectionKey> readyKeys; while (!isInterrupted()) { synchronized (this) {} // LOCKING OCCURS HERE try { ready = selector.select(5000); } catch (IOException e) { e.printStackTrace(); continue; } if (ready == 0) { continue; } readyKeys = selector.selectedKeys(); for (SelectionKey key : readyKeys) { readyKeys.remove(key); if (!key.isValid()) { continue; } if (key.isReadable()) { ... } } } } } 

This simple lock allows register() occur before the thread continues the next select loop. As far as I checked, this works as expected.

Questions: Is this a “good” way to do this or are there any serious flaws? Would it be better to use List or Queue (as suggested here ) to store channels for registration or more complex blocking like this instead? What are the pros and cons of this? Or are there any “even better” ways?

+10
java multithreading nio
source share
3 answers

I'm really surprised that locking collection with an empty block is not removed at compile time. Pretty cool that it works. I mean that it works, it is proactive, this is not the most beautiful approach, but it works. This is better than a dream, because it is predictable, and since you use awakening, you know that progress will be made as necessary, and not with periodic updates, if you simply rely on the timeout of choice.

The main disadvantage of this approach is that you say that calls register the trump card of everything else, even serving requests. What may be true in your system, but usually it is not, I would say that this is a possible problem. A small problem, which is more promising thinking, is that you are blocking SelectorThread itself, which in this case is a larger object. Not bad, it doesn't matter, although when you expand, this castle will simply document and take into account when other clients use this class. Personally, I would like to make another castle to avoid any unforeseen future dangers.

Personally, I like queuing methods. They assign roles to your threads, such as the master and workers. While all types of control occur on the host computer, for example, after each selection check for more registrations from the queue, clear and process any reading tasks, process any changes in the general connection settings (disconnects, etc.) ... The "bs" <Model w390> seems to fit quite well with this model, and it is a pretty standard model. I don’t think this is bad, because it makes the code a little less cracked, more verifiable and easier to read imo. It just takes more time to write out.

Although I admit that a lot of time has passed since I last wrote this material, there are other libraries that take care of the queue for you.

The Grizzly Nio Framework , while a bit old, the last time I used it, the main runloop was pretty good. He sets up many queues for you.

Apache Mina Similarly, it provides a queue structure.

But I mean, in the end, it depends on what you are working on.

  • Is this a project for one person who just needs to work with a wireframe?
  • Is this a piece of code that you want to live for years?
  • Is this a piece of production code that you are repeating?

If you do not plan to use this as the main part of the service you provide to clients, I would say that your approach is in order. This may ultimately have a maintenance problem.

+3
source share

Just process Selector, etc., since it is not thread safe, perform all actions associated with a specific action in the same thread as Darron.

The NIO concurrency selector model is shit. I have to call it because it is a huge waste of time for anyone trying to learn it. In the end, the conclusion is to forget about it, not for simultaneous use.

+4
source share

All you need is wakeup() before register() and, in the select loop, a short sleep before continuing if "ready" is zero to give register() ability to run. No additional synchronization: this is already bad enough; don't make it worse I'm not a fan of these lines of things for registering, canceling, changing operations with interest, etc.: they simply organize things that can really be done in parallel.

+3
source share

All Articles