0

It seems that in implementing servers that rely on java nio, the following practice is standard:

Use a single thread (and a single selector) for reads:

ByteBuffer buffer = . . .
selector.select()
...
channel.read(buffer)
if (isRequestComplete(buffer))
    processRequest(buffer) //will run in a separate thread

void processRequest(ByteBuffer buffer)
    new Thread(new Handler(buffer)).start()

Yes, I'm elliding a substantial amount of code

My question is not about the mechanics of selecting/reading from a channel, but rather the visibility semantics of the #buffer being read in a separate thread than the selector thread. I can see nothing in the javadoc stating that reading from a ByteBuffer in Thread A ('Handler' in above) is guaranteed to see the write to the ByteBuffer in Thread B ('Selector' in above).
Now, it seems to me that the code above simply is not multi-thread-safe, i.e. it's wrong. But I've seen the same pattern in numerous tutorials and even some codebases (always without even referencing the visibility concern); so I'm wondering if I'm missing something obvious.

Note: I'm specifically focussing on the situation where the 'Handler' Thread only ever reads from #buffer - it never writes new bytes into it

igaz
  • 392
  • 3
  • 9

1 Answers1

1

This actually seems OK. What you need is to prove that the write in the selector thread "happens-before" the read in the handler thread. According to the memory visibility rules, actions in the same thread happen in program order. The creation of a new thread also establishes happens-before. So the write happens-before thread creation which happens-before the read.

This would also be OK if you pass it into e.g. an ExecutorService.

Steven Schlansker
  • 37,580
  • 14
  • 81
  • 100
  • 1
    Yes, excellent point. Indeed, another way to phrase my question is "where is the happens-before"? I had forgotten about the JMM regarding the creation/starting of a Thread. Obviously, you could also use ConcurrentQueues, explicit synchronization (blecch) and ExecutorService.execute(new Handler(buffer)), et al -- all should suffice. – igaz Mar 17 '13 at 06:31