Third Lombok Synchronized Example

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.

There are 799 words in this article.