5 Replies Latest reply: Mar 3, 2011 1:19 PM by 844506 RSS

    Blocking caused by java.util.Calendar.setWeekCountData

      I'm seeing a lot of latency in a WebLogic app with several threads (10) creating date objects. This is the trace causing the problems:

      . java.util.Calendar.setWeekCountData(Locale)
      . . java.util.Calendar.<init>(TimeZone, Locale)
      . . . java.util.GregorianCalendar.<init>(TimeZone, Locale)
      . . . . java.util.Calendar.getInstance(TimeZone, Locale)
      . . . . . (my method)

      It is causing almost all of the blocking shown in the snapshot below.

      I'm using JRockit 1.4.2_17 (build 1.4.2_17-b06)
      BEA JRockit(R) (build R27.6.0-50_o-100423-1.4.2_17-20080626-2105-windows-ia32, compiled mode)

      Any ideas how I can get around this blocking?


        • 1. Re: Blocking caused by java.util.Calendar.setWeekCountData
          Staffan Larsen
          Any particular reason that you create new Calendar objects all the time? Is it possible for you to create the Calendar once and keep it around in your code? That would avoid the synchronization.

          • 2. Re: Blocking caused by java.util.Calendar.setWeekCountData
            I'm pulling back hundreds/thousands of dates from a database where they are stored in GMT and converted to any number of different time zones at run time. In order to return back an array of dates with different time zones to higher level methods, it seems like I need a separate Calendar object for each one.

            Once I start processing on multiple threads, I see the blocking. So, the problem is that I don't know how to get around this since it is in the actual java.util.Calendar class.
            • 3. Re: Blocking caused by java.util.Calendar.setWeekCountData
              we hit exactly the same problem as the post above. please note that it only happens if multiple threads are doing Calendar.getInstance concurrently. if it's done sequentially, there won't be any fat locks.
              We used jrrt-3.0.0-1.5.0
              here's the stack trace we got:

              "[ACTIVE] ExecuteThread: '135' for queue: 'weblogic.kernel.Default (self-tuning)'" id=196 idx=0x31c tid=8755 prio=5 alive, in native, blocked, daemon
              -- Blocked trying to get lock: java/util/Hashtable@0x98f86a0[unlocked]
              at jrockit/vm/Threads.waitForUnblockSignal()V(Native Method)
              at jrockit/vm/Locks.fatLockBlockOrSpin(Locks.java:1674)[optimized]
              at jrockit/vm/Locks.lockFat(Locks.java:1775)[optimized]
              at jrockit/vm/Locks.monitorEnterSecondStageHard(Locks.java:1311)[optimized]
              at jrockit/vm/Locks.monitorEnterSecondStage(Locks.java:1258)[optimized]
              at jrockit/vm/Locks.monitorEnter(Locks.java:2455)[optimized]
              at java/util/Hashtable.get(Hashtable.java:335)[optimized]
              at java/util/Calendar.setWeekCountData(Calendar.java:2240)[optimized]
              at java/util/Calendar.<init>(Calendar.java:897)[inlined]
              at java/util/GregorianCalendar.<init>(GregorianCalendar.java:574)[inlined]
              at java/util/Calendar.cr
              • 4. Re: Blocking caused by java.util.Calendar.setWeekCountData

                The JDK includes a static Hashtable that is queried at each getInstance() call (through the setWeekCountData). As the Hashtable.get() is synchronized it will act as a monitor. Hence only one thread at a time can query this Hashtable. I guess the Hashtable was supposed to improve performance by caching locales but it seems that this is not the case when creating Calendar objects concurrently.
                • 5. Re: Blocking caused by java.util.Calendar.setWeekCountData
                  The problem is still present in JDK 6 Update 21.

                  If you can't workaround the Calendar class, e.g. by using java.util.Date or much better JodaTime instead, you must fix it, by patching java.util.Calendar in jre/lib/rt.jar.

                  1. Create a class Calendar within the package java.util (will compile despite it is in a java.util package)
                  2. Copy all the source code from the original Calendar class into your class
                  3. Locate:
                      private static Hashtable<Locale, int[]> cachedLocaleData = new Hashtable<Locale, int[]>(3);
                  4. Replace it with:
                     private static Map<Locale, int[]> cachedLocaleData = new HashMap<Locale, int[]>(3);
                     static {
                        Locale[] availableLocales = Locale.getAvailableLocales();
                        for (int i = 0; i < availableLocales.length; i++) {
                              ResourceBundle bundle = LocaleData.getCalendarData(availableLocales);
                  int[] data = new int[2];
                  data[0] = Integer.parseInt(bundle.getString("firstDayOfWeek"));
                  data[1] = Integer.parseInt(bundle.getString("minimalDaysInFirstWeek"));
                  cachedLocaleData.put(availableLocales[i], data);
                  It will now load cachedLocaleData at class loading, initializing it only once. The threadsafe Hashtable was replaced with a non threadsafe HashMap.
                  Keep the method setWeekCountData(Locale desiredLocale) as is. It is no longer threadsafe, but since cachedLocaleData was initialized with the week count data from all available locales at class loading, it should no longer add additional week count data.
                  5. Finally replace java.util.Calendar in rt.jar with the new version
                  This is by all means a suggestion only.