Recently I was reading an informative post about the differences between synchronized vs ReentrantLock by Javin Paul . He emphasises on the advantages of the latter, but does not withhold some downsides, which are related to the cumbersome try-finally block needed for proper usage.

While agreeing with his statements I brooded about a thought, that always bothers me when it comes down to synchronization. Both approaches mix up separate concerns – synchronization and the functionality of the synchronized content – which hampers testing those concerns one by one.

Being the explorative type, I picked up a solution for this problem that I already tried in the past. However, at that time I did not like the programming pattern too much. This was because of its verboseness due to an anonymous class. But having Java 8 and Lambda expressions at hand I thought it might be worth reconsidering. So I copied the ‘counter’ part of Javin Paul’s example, wrote a simple test case and started refactoring. This was the initial situation:

class Counter { private final Lock lock; private int count; Counter() { lock = new ReentrantLock(); } int next() { lock.lock(); try { return count++; } finally { lock.unlock(); } } }

One can clearly see the ugly try-finally block that produces a lot of noise around the actual functionality . The idea is to move this block into its own class that serves as a synchronization aspect to a kind of operation that does the incremental. The next snippet shows how such a newly created Operation interface may look like and how it can be used by a Lambda expression :

class Counter { private final Lock lock; private int count; interface Operation<T> { T execute(); } Counter() { lock = new ReentrantLock(); } int next() { lock.lock(); try { Operation<Integer> operation = () -> { return count++; }; return operation.execute(); } finally { lock.unlock(); } } }

In the following class extracting step the Synchronizer type is introduced to serve as an executor that ensures a given Operation is performed within proper synchronization boundaries:

class Counter { private final Synchronizer synchronizer; private int count; interface Operation<T> { T execute(); } static class Synchronizer { private final Lock lock; Synchronizer() { lock = new ReentrantLock(); } private int execute( Operation<Integer> operation ) { lock.lock(); try { return operation.execute(); } finally { lock.unlock(); } } } Counter() { synchronizer = new Synchronizer(); } int next() { return synchronizer.execute( () -> { return count++; } ); } }

If I am not completely mistaken this should do the same as the initial class. Well, the tests were green, but plain JUnit tests do usually not help much regarding concurrency. But with one last change it is at least possible to verify the proper invocation sequence by a unit test to ensure synchronization:

public class Counter { final Synchronizer<Integer> synchronizer; final Operation<Integer> incrementer; private int count; public Counter( Synchronizer<Integer> synchronizer ) { this.synchronizer = synchronizer; this.incrementer = () -> { return count++; }; } public int next() { return synchronizer.execute( incrementer ); } }

As you can see the Operation and Synchronizer have been moved to their own files. This way the synchronization aspect is provided and can be tested as a seperate unit. The Counter class now uses the constructor to inject a synchronizer instance . Furthermore the incrementation operation has been assigned to a field named ‘incrementer’. To ease testing a bit the final fields’ visibility has been opened to default. A test using Mockito for e.g. spying on the synchronizer could now ensure the proper synchronization call like this:

@Test public void synchronization() { Synchronizer<Integer> synchronizer = spy( new Synchronizer<>() ); Counter counter = new Counter( synchronizer ); counter.next(); verify( synchronizer ).execute( counter.incrementer ); }

Usually, I am not overly excited about using method invocation verification, as this generates a very tight coupling between unit and test case. But given the circumstances above, it does not look as a too bad compromise to me. However I am just doing first warmups with Java 8 and Lambda expressions and maybe I am missing something on the concurrency side too – so what do you think?