In a previous post I complained about the Java Concurrency example. It showed how unimpressive and needlessly complicated threading can be in Java. What bothers me most isn't the concept of wait() and notify(). It is the decision to explain wait() and notify() before simpler methods of synchronization.
It happens that Java has quite a few helper classes to make synchronization much simpler. The Semaphore is one of those classes. I have constructed a simpler version of the Drop class using two Semaphores.
public class Drop { private static final int MAX_MESSAGE = 10; private String[] messages = new String[MAX_MESSAGE]; private int next_available; private Semaphore taking = new Semaphore(0, true); private Semaphore putting = new Semaphore(MAX_MESSAGE, true); public void put(String message) { try { putting.acquire(); } catch (InterruptedException e) { } synchronized (messages) { messages[next_available] = message; next_available++; } taking.release(); } public String take() { String message; try { taking.acquire(); } catch (InterruptedException e) { } synchronized (this) { next_available--; message = messages[next_available]; } putting.release(); return message; } }
There are three conceptual pieces to that make this new Drop work. The first and second are two Semaphores, putting and taking. The third piece is the synchronized code block
- The putting Semaphore protects against concurrent additions, and overflow.
- The taking Semaphore protects against concurrent removals, and underflow.
- The synchronized code block it utilizes the intrinsic lock on Drop creating an atomic section. Thereby protecting against concurrent manipulations of the messages array and next_available index into it.
These three pieces are much easier to understand than a broadcast system. Although we understand (or guess) that the underlying Semphore is implemented with the broadcasting wait() and notify() system.
Utilizing the provided utilities the example has become far simpler. There's no need to check the state of the Drop when the thread has resumed. There are no concerns of cascading execution of tasks.
Synchronization in Java could be presented as a simple use of the available utilities.