Newsletter sign-up
View all newsletters

Sign up for our technology specific newsletters.

Enterprise Java
Email Address:

Programming Java threads in the real world, Part 3

Roll-your-own mutexes and centralized lock management

  • Digg
  • Reddit
  • SlashDot
  • Stumble
  • del.icio.us
  • Technorati
  • dzone

Page 2 of 5

So, roll your own

You can implement the two-lock strategy by synchronizing on something other than the containing object. Rather than synchronizing the methods, you can define two local variables to use as locks and synchronize on them:

1| class Complicated_and_thread_safe
2| {
3|     private long a, b;
4|     private long x, y;
5| 
6|     private Object ab_lock = new int[];
7|     private Object xy_lock = new int[];
8| 
9|     // partition 1, functions use a and/or b
10| 
11|     public void use_a()      { synchronized(ab_lock){
 /*...*/ } }   
12|     public void use_b()      { synchronized(ab_lock){
/*...*/ } }   
13|     public void use_a_and_b(){ synchronized(ab_lock){
/*...*/ } }   
14| 
15|     // partition 2, functions use x and/or y
16| 
17|     public void use_x()      { synchronized(xy_lock){
 /*...*/ } }
18|     public void use_y()      { synchronized(xy_lock){
/*...*/ } }
19|     public void use_x_and_y(){ synchronized(xy_lock){
/*...*/ } }
20| 
21|     // partition 3, functions use a, b, x, and y
22| 
23|     public void use_everything()
24|     {   synchronized(ab_lock)       // grab both locks
25|         {   synchronized(xy_lock)
26|             {   /*...*/
27|             }
28|         }
29|     }
30|         
31|     public void use_everything_else()
32|     {   synchronized(ab_lock)
33|         {   synchronized(xy_lock)
34|             {   /*...*/
35|             }
36|         }
37|     }
38| }


I haven't synchronized the methods themselves in this example. (Remember, synchronizing a method is effectively the same thing as wrapping all the code in the method in a synchronized(this){...} block.) Instead, I'm providing a unique lock for each partition (ab_lock and xy_lock) and then explicitly synchronizing on these individual locks.

Java associates locks with objects (instance of some class that extends Object, so I can't use primitive-type variables as locks here. I don't want to spend unnecessary time calling constructors and doing other initialization operations on complicated objects, however. Consequently, the locks themselves are declared as the simplest possible Object -- an array.

Arrays in Java are first-class objects: they implicitly extend the Object class. (If you don't believe me, compile the following code:

1| public class foo
2| {   static Object ref = new int[]{ 10 };
3|     
4|     public static void main( String[] args )
5|     {   System.out.println( ref.toString() );
6|     }
7| }


The class compiles just fine. Not only does the implicit cast from the array to Object work (because Object is a base class of all arrays), but the println() correctly invokes the compiler-generated toString() override (which prints absolutely nothing useful -- but you can't have everything). I've used a one-element array for my lock, rather than something like an Integer, because arrays come into existence very efficiently. For example, there's no constructor call.

In the foregoing example, it's critical that methods that acquire both locks always acquire them in the same order, otherwise we end up in the Wilma-and-Betty deadlock scenario discussed last month. Acquiring multiple locks is a commonplace enough problem that some operating systems have system calls for this purpose. It would be nice to have an easy way to acquire multiple locks, in Java, without having to worry about the order-of-acquisition problem. The remainder of this month's column describes one way to do that.

  • Digg
  • Reddit
  • SlashDot
  • Stumble
  • del.icio.us
  • Technorati
  • dzone
Comments (1)
Login
Forgot your account info?

new Object()By Anonymous on February 17, 2009, 5:16 pmInstead of 'new int[]' you can use 'new Object()'

Reply | Read entire comment

View all comments

Add comment
Anonymous comments subject to approval. Register here for member benefits.
Have a JavaWorld account? Log in here. Register now for a free account.
Resources
  • All the real code (the stuff in the com.holub.asynch package) is available in the "Goodies" section on my Web site http://www.holub.com