This is a continuation of my look into concurrency in Java.
I found a library called Lombok that uses annotations to reduce boilerplate code. Instead of using annotations for metadata, it uses hidden APIs to alter the class files. Some people do not like this because it is voodoo, but it seems to get the job done. There is a possibility that at some point in the future it will stop working.
For threading, it has an annotation @Synchronized. It has other annotations as well. The voodoo for the @Synchronized annotation is that it will create a private object and inject a synchronized object locking on the private object that it created. There is another version that takes a java.lang.String as a parameter (or element as they are called for annotations). If you use this version, then you provide the name of the object you want to lock on.
Here is what the javadoc says: “Almost exactly like putting the ‘synchronized’ keyword on a method, except will synchronize on a private internal Object, so that other code not under your control doesn’t meddle with your thread management by locking on your own instance.” So I suppose you could do everything that this annotation does for you by providing your own objects. But using Lombok makes your code a lot easier to read.
It would be great if every time you used the “synchronized” keyword the javac compiler created a unique object for that method or block.
In the discussions on LinkedIn, a few people have mentioned that using the synchronized keyword can cause performance issues. I do not know if creating and using a different object degrades performance. I got the impression from the discussions that the performance issue is due to applications repeatedly getting a lock on the same object. I have read that object creation is now cheap, so I do not think that using different private objects for locks would be that big of a deal.
But I do think that it helps prevent deadlocks. I got a few examples of deadlocks from the internet, including one from the Really Big Tutorial, and one from the LinkedIn discussions. I was able to refactor them with Lombok to prevent the deadlocks. I did have to use both forms of the @Synchronized annotation: One with the optional java.lang.String element, and one without. Only using the no-element annotation did not prevent the deadlock.
I will post the deadlock examples I found on the internet as well as my changes with Lombok.
Image from Wikipedia article about Mataram (city), the largest city on Lombok and the capital of the province containing Lombok, assumed allowed under Fair Use.
There is no statistically relevant difference in performance between ‘synchronized’ as a keyword on a method and @Synchronized, so regardless of what you do, those concerns you mentioned are valid. Lombok really just does what it says: It prevents programming bugs which occur when two unrelated pieces of code happen to use the same lock object entirely by accident. You can see this bug in action on a live VM:
public void test() {
synchronized (Thread.class) {
while (true) { Thread.sleep(1000L); }
// As the above never quits, we hold the lock on the Thread.class object permanently.
}
}
run that method in a thread somewhere, then, while that thread is running, create another thread. It won’t work. Thread locks on Thread.class. It should have locked on a private object to avoid me being able to just hose Thread’s internal mechanics entirely by holding on to a lock that it needs for no reason.
To: Reinier Zwitserloot
Thanks for the response. As you may have gathered from other posts, I am not an expert on concurrency. I am starting to figure this out.
Lombok may not be the fastest way to make code thread-safe, but it does make it clearer. More clarity is better in my opinion.