Chapter 3 was about design. He discussed immutability, shared mutability, and isolated mutability.
In Chapter 4 he went over some of the concurrency APIs that were introduced in Java 5.
The Fork/Join framework was not as much of a beast as I thought (although I am not claiming to know the whole thing). It is a lot like dealing with Callables, Futures and ExecutorServices and thread pools. First, you create a ForkJoinPool. Then you make a class that extends a child class of ForkJoinTask. There are two, and they each have a method called “compute” that actually does the work, sort of like Callable.call(). RecursiveAction.compute() returns void, and RecursiveTask.compute() returns an object.
Your grandchild class of ForkJoinTask might instantiate a few copies of itself in the compute() method. You build up a java.util.Collection of them, and call invoke() or invokeAll() to start the calculations. I guess this is sort of like ExecutorService.submit(). Then you call ForkJoinTask.join to bring the results together. This is all kicked off by ForkJoinPool.invoke() (which returns an object) or ForkJoinPool.invokeAll() (which returns a List of Future objects). ForkJoinPool implements the ExecutorService interface, and ForkJoinTask implements the Future interface. So in a way it is like Callables and Futures, although I am not too clear right now when you would use one versus the other.
He deals briefly with CountDownLatch and CyclicBarrier. He states that there are better ways to do concurrency than Threads and locking, so I did not spend a whole lot of time on these. “CyclicBarrier” sounds like something out of science fiction.
He touched on AtomicLong, and that it is a good way to make a long variable thread-safe. There are also AtomicInteger and AtomicBoolean classes. I wonder why there is no AtomicFloat or AtomicDouble. The API for these says that these should not be used as replacements for the java.lang.Integer and java.lang.Long classes. Yet if you look at the Really Big Tutorial, they kind of do exactly that.
There was also a section on concurrent collections. He pointed out that they have better performance that older collection classes in addition to being thread safe, although he did not spend a whole lot of time on them.
There was a section on the classes in the java.util.concurrent.locks package. It looks like it is a good substitute for the synchronized keyword. although it is pretty verbose. I made a few classes that set and manipulate a few variables, with one using “synchronized” and two others using locks. One used a separate RentrantLock for each variable, and the other used one for the whole class. The main class just goes through a loop, calls some methods and sees how long it took. The class using the “synchronized” keyword was faster. I know that the Lock objects are better at preventing deadlocks, but it does seem like they sacrificed some speed. Perhaps I need to find a better comparison than the one I made.
Dr S. will be here next week for the Austin JUG meeting. Hopefully by then I will be through chapter 6, Software Transactional Memory. It is the longest chapter in the book. I will have to set up some projects for Clojure and Scala. I am doing the Java stuff with Gradle, and I think I am learning as much about Gradle as I am about concurrency.
Image from the Ada Gospels, a 9th-century manuscript housed in the Trier State Library. It gets its name from a dedication to Ada, the sister of Charlemagne, and is an example of Carolingian illumination. Image assumed allowed under Fair Use.