Here is another installment of my exploration into concurrency in Java. I have written about finding the Lombok library which uses annotations to reduce boilerplate in Java code.
One of the annotations provided by Lombok is @Synchronized. It is to replace the “synchronized” keyword and prevent some of the problems that can come with using the “synchronized” keyword. There are other annotations available via Lombok, but I have not looked at them.
Here is the third example of a program with a deadlock using the “synchronized” keyword that I refactored with Lombok. I got this example from the Java 2S site.
For this one I have also included the output of each of the programs.
Here is the program:
package newpackage2; // from http://www.java2s.com/Code/Java/Threads/Threaddeadlock.htm public class Deadlock extends Object { private String objID; public Deadlock( String id ) { objID = id; } public synchronized void checkOther( Deadlock other ) { print( "entering checkOther()" ); try { Thread.sleep( 2000 ); } catch ( InterruptedException x ) { x.printStackTrace(); } print( "invoke 'other.action()'" ); other.action(); print( "leaving checkOther()" ); } public synchronized void action() { print( "entering action()" ); // simulate some work here try { Thread.sleep( 500 ); } catch ( InterruptedException x ) { x.printStackTrace(); } print( "leaving action()" ); } public void print( String msg ) { threadPrint( "objID=" + objID + " - " + msg ); } public static void threadPrint( String msg ) { String threadName = Thread.currentThread().getName(); System.out.println( threadName + ": " + msg ); } public static void main( String[] args ) { System.out.println( "Starting Deadlock" ); final Deadlock obj1 = new Deadlock( "Thread 1" ); final Deadlock obj2 = new Deadlock( "Thread 2" ); Runnable runA = new Runnable() { public void run() { obj1.checkOther( obj2 ); } }; Thread thread = new Thread( runA, "A" ); thread.start(); try { Thread.sleep( 200 ); } catch ( InterruptedException x ) { x.printStackTrace(); } Runnable runB = new Runnable() { public void run() { obj2.checkOther( obj1 ); } }; Thread threadB = new Thread( runB, "B" ); threadB.start(); try { Thread.sleep( 5000 ); } catch ( InterruptedException x ) { x.printStackTrace(); } threadPrint( "finished sleeping" ); threadPrint( "about to interrupt() threadA" ); thread.interrupt(); try { Thread.sleep( 1000 ); } catch ( InterruptedException x ) { x.printStackTrace(); } threadPrint( "about to interrupt() threadB" ); threadB.interrupt(); try { Thread.sleep( 1000 ); } catch ( InterruptedException x ) { x.printStackTrace(); } threadPrint( "did that break the deadlock?" ); System.out.println( "Ending method main" ); } // end method main } // end class
Here is its output:
Starting Deadlock A: objID=Thread 1 - entering checkOther() B: objID=Thread 2 - entering checkOther() A: objID=Thread 1 - invoke 'other.action()' B: objID=Thread 2 - invoke 'other.action()' main: finished sleeping main: about to interrupt() threadA main: about to interrupt() threadB main: did that break the deadlock? Ending method main
There is a line that says “Ending method main”, but it does not end unless you kill the program.
Here is the program refactored with Lombok:
package newpackage2; // example from http://www.java2s.com/Code/Java/Threads/Threaddeadlock.htm // refactored to use Lombok import java.util.UUID; import lombok.Synchronized; public class DeadlockLombok extends Object { private String objID; private final Object someObject = new Object(); public DeadlockLombok( String id ) { objID = id; } // public synchronized void checkOther(DeadlockLombok other) { @Synchronized public void checkOther( DeadlockLombok other ) { print( "entering checkOther()" ); try { Thread.sleep( 2000 ); } catch ( InterruptedException x ) { x.printStackTrace(); } print( "invoke 'other.action()'" ); other.action(); print( "leaving checkOther()" ); } // @Synchronized public void action() { // does not work @Synchronized( "someObject" ) public void action() { // works // public synchronized void action() { print( "entering action()" ); // simulate some work here try { Thread.sleep( 500 ); } catch ( InterruptedException x ) { x.printStackTrace(); } print( "leaving action()" ); } public void print( String msg ) { threadPrint( "objID=" + objID + " - " + msg ); } public static void threadPrint( String msg ) { String threadName = Thread.currentThread().getName(); System.out.println( threadName + ": " + msg ); } public static void main( String[] args ) { System.out.println( "Starting DeadlockLombok" ); final DeadlockLombok obj1 = new DeadlockLombok( "Thread 1" ); final DeadlockLombok obj2 = new DeadlockLombok( "Thread 2" ); Runnable runA = new Runnable() { public void run() { obj1.checkOther( obj2 ); } }; Thread thread = new Thread( runA, "A" ); thread.start(); try { Thread.sleep( 200 ); } catch ( InterruptedException x ) { x.printStackTrace(); } Runnable runB = new Runnable() { public void run() { obj2.checkOther( obj1 ); } }; Thread threadB = new Thread( runB, "B" ); threadB.start(); try { Thread.sleep( 5000 ); } catch ( InterruptedException x ) { x.printStackTrace(); } threadPrint( "finished sleeping" ); threadPrint( "about to interrupt() threadA" ); thread.interrupt(); try { Thread.sleep( 1000 ); } catch ( InterruptedException x ) { x.printStackTrace(); } threadPrint( "about to interrupt() threadB" ); threadB.interrupt(); try { Thread.sleep( 1000 ); } catch ( InterruptedException x ) { x.printStackTrace(); } threadPrint( "did that break the deadlock?" ); System.out.println( "End method main" ); } // end method main } // end class
Here is the output of the refactored program:
Starting DeadlockLombok A: objID=Thread 1 - entering checkOther() B: objID=Thread 2 - entering checkOther() A: objID=Thread 1 - invoke 'other.action()' A: objID=Thread 2 - entering action() B: objID=Thread 2 - invoke 'other.action()' B: objID=Thread 1 - entering action() A: objID=Thread 2 - leaving action() A: objID=Thread 1 - leaving checkOther() B: objID=Thread 1 - leaving action() B: objID=Thread 2 - leaving checkOther() main: finished sleeping main: about to interrupt() threadA main: about to interrupt() threadB main: did that break the deadlock? End method main
Image from the Wikipedia page for the Indonesian province of West Java, assumed allowed under Fair Use.