Name: vi73552 Date: 06/04/99 We noticed a deadlock between java.util.Calendar, and java.util.Date. If neither class has ever been loaded, and thread A calls Calendar.getInstance(), and thread B simultaneously creates a new Date, the threads can deadlock. Obviously, this only happens if you get the race condition just exactly right, but I have written a simple program illustrating the problem that the classes get themselves into: Program: import java.util.Hashtable; /** * Demonstrates a deadlock that can occur if one thread is * calling Calendar.getInstance() for the first time ever * while another thread is creating the first Date ever. * * Simplified classes are used to illustrate the bug and * to force the race condition to happen the right way. * * If you replace the fake classes with the real ones from * the java.util package, then you can also see it, but * only if you're "lucky." */ public class DateCalendarDeadlock { public static void sleep(long millis) { try { Thread.sleep(millis); } catch (Exception ex) { } } public static void main (String [] args) throws Exception { System.out.println("Creating threads."); Thread threadA = new Thread() { public void run() { MyCalendar.getInstance(); System.out.println("Thread A: Exiting"); } }; Thread threadB = new Thread() { public void run() { DateCalendarDeadlock.sleep(5 * 1000); System.out.println("Thread B: Started, calling new MyDate()..."); MyDate myDate = new MyDate(); System.out.println("Thread B: Exiting"); } }; threadA.start(); threadB.start(); threadA.join(); threadB.join(); System.out.println("Program completed normally."); } } // Vastly simplified version of java.util.Calendar class MyCalendar { // Comment out the 'synchronized' and the deadlock disappears... public static synchronized MyCalendar getInstance() { System.out.println("Thread A: Acquired MyCalendar lock; waiting for Thread B to start..."); // We've got MyCalendar locked, so wait for Thread B to deadlock. DateCalendarDeadlock.sleep(10 * 1000); System.out.println("Thread A: Calling new MyGregorianCalendar()..."); // Thread A gets deadlocked here, because Thread B has MyGregorianCalendar locked... return new MyGregorianCalendar(); } } // Vastly simplified version of java.util.GregorianCalendar class MyGregorianCalendar extends MyCalendar { public MyGregorianCalendar() { // Thread B gets deadlocked here, trying to call the // MyCalendar constructor. super(); System.out.println("The deadlock did not occur."); } } // Vastly simplified version of java.util.MyDate class MyDate { static MyCalendar staticCal; static { System.out.println("Thread B: In MyDate static constructor, calling new MyGregorianCalendar()..."); staticCal = new MyGregorianCalendar(); } public MyDate() { System.out.println("Thread B: In MyDate Instance Constructor."); } } Output: PROMPT: java -version java version "1.1.7B" PROMPT: java -fullversion java full version "JDK1.1.7U" PROMPT: java DateCalendarDeadlock Creating threads. Thread A: Acquired MyCalendar lock; waiting for Thread B to start... Thread B: Started, calling new MyDate()... Thread B: In MyDate static constructor, calling new MyGregorianCalendar()... Thread A: Calling new MyGregorianCalendar()... ^C (Had to CTRL-C out of it, program was hung...) (Review ID: 83919) ======================================================================