fmi / java-course

Материали към курса "Съвременни Java технологии"

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

EchoServer.java has unreachable if statement.

DenisBelinov opened this issue · comments

According to the documentation about thejava.nio.channels.Selector:

This method performs a blocking selection operation. It returns only after at least one channel is selected, this selector's wakeup method is invoked, or the current thread is interrupted, whichever comes first.

This means that the if (readyChannels == 0) { is redundant and unreachable in https://github.com/fmi/java-course/blob/master/11-network/snippets/echoclientserver/nio/EchoServer.java#L31

Thanks for raising this. You are right, still, there are two scenarios, in which the method will return 0: "this selector's wakeup method is invoked, or the current thread is interrupted". The documentation of Selector.select() also mentions it: "Returns: The number of keys, possibly zero, whose ready-operation sets were updated".

If you own the code, you have control on the explicit wakeup and interrupt calls, and you may know that you do not invoke any of those, however, this could change in future. Also, your code should be prepared to be interrupted, if it is run within a Java framework or from some worker thread (e.g. during shutdown of an ExecutorService). There is also some small probability for a so-called "spurious wakeup" to occur: a waiting thread to exit its waiting state although it has not been notified. Spurious wakeups are extremely rare events but may happen (they are triggered by OS-level events) and it is advisable for the application code to be ready to handle them.

Bottom line: the check is not unreachable code (if it were, it would not compile). If omitted, the code will continue working in 99% of the cases, but to be on the safe side, it can be kept. In the literature, there are code snippets both with and without this check.

I see, thank you for the clarification! I should have read the whole doc it seems.

That being said and given that NIO is really confusing at first, when we were looking at the code snip in the lectures and lab I was left with the impression that select() was non-blocking. This if having the System.out.println("Still waiting for a ready channel..."); and the Thread.sleep(SLEEP_MILLIS); looks like handling of a non-blocking select().

I am very new to this area of programming, so please correct me if I am wrong:

  1. Given that select() returns zero only on those said occasions, doesn't it make more sense to handle that differently instead of just sleeping and resuming the process of selecting afterwards. I understand that you've put the if there to show that it is indeed reachable, but the content of the if block made it confusing for me.
  2. If we would just sleep and resume, do we really need that if? Wouldn't selector.selectedKeys(); just return an empty set which doesn't seem to break the logic.

PS:

if it were, it would not compile

Wow, I did not know that. Nice!

Some further comments:

  • the content of the if-block is indeed confusing, so we have fixed the lecture slide and code snippet snippet
  • Besides the blocking select() being interrupted, there are also other ways where it could complete normally and still return 0, unfortunately, is very vague in the javadoc of the method: it says

Returns: The number of keys, possibly zero, whose ready-operation sets were updated.

More clarifications were difficult to find, until I came across this passage in O'Reilly's Java NIO book:

The value returned by the select operation is the number of keys whose operation ready sets were modified in Step 2, not the total number of channels in the selection key set. The return value is not a count of ready channels, but the number of channels that became ready since the last invocation of select( ). A channel ready on a previous call and still ready on this call won’t be counted, nor will a channel that was ready on a previous call but is no longer ready. These channels could still be in the selection key set but will not be counted in the return value. The return value could be 0.

This means, the return value could happen to be 0 and at the same time the selected key set be non-empty. Thus, the "if" is necessary, but it's enough to just "continue;" in its body, without sleeping.

Thanks for your 11-months patience. I am closing this issue as I consider the case closed.