Bug 32311 - Performance: fmt:formatDate regarding calls to Calendar.getInstance
Summary: Performance: fmt:formatDate regarding calls to Calendar.getInstance
Alias: None
Product: Taglibs
Classification: Unclassified
Component: Standard Taglib (show other bugs)
Version: 1.0.4
Hardware: PC Windows XP
: P2 normal (vote)
Target Milestone: ---
Assignee: Tomcat Developers Mailing List
Depends on:
Blocks: 50265
  Show dependency tree
Reported: 2004-11-19 11:43 UTC by Harm Jan Nijlunsing
Modified: 2011-01-01 15:18 UTC (History)
0 users

Fix+Test patch (8.30 KB, patch)
2007-09-30 00:46 UTC, Henri Yandell
Details | Diff
Fix+More Tests (9.05 KB, patch)
2007-10-15 22:35 UTC, Henri Yandell
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Harm Jan Nijlunsing 2004-11-19 11:43:22 UTC
When loadtesting our site with 10 users to a page which makes a lot of use of
the fmt:formatdate, the hits / seconds drop and fluctuate tremondously between 5
hits / sec and 20 hits per sec.
With 1 or 2 users the hits per second maintain constantly at 20 hits / sec.
Using Weblogic 6.1 SP4, with 15 (default) execute threads, memory / garbage
collection is not a problem.
After creating threaddumps is appears that almost all threads have these
stacktraces on the top: 
       at java.util.Calendar.getInstance(Calendar.java:829)
       at java.text.SimpleDateFormat.initialize(SimpleDateFormat.java:326)
       at java.text.SimpleDateFormat.<init>(SimpleDateFormat.java:317)
       at java.text.DateFormat.get(DateFormat.java:645)
       at java.text.DateFormat.getTimeInstance(DateFormat.java:411)

And are all "waiting on monitor XXXXX", it seems these calls are blocking each
other, possible due to the fact that getInstance is synchronized?

Other pages which are not using this tag are not a problem.
Comment 1 Harm Jan Nijlunsing 2004-11-23 10:40:18 UTC
Since the date patterns, are likely to stay the same on each page. (Because 
usually the date is dynamic, and the date patterns static). Would it be an idea 
to have a pool of SimpleDateFormatters each with its own pattern + locale, so 
we could reuse the same patterns to avoid unnecessary calls to 

e.g. in org.apache.taglibs.standard.tag.common.fmt.FormatDateSupport

Something like:
    static Map sdfCache=new HashMap();

    public synchronized SimpleDateFormat getSimpleDateFormat(String pattern, 
Locale locale) {
    	System.out.println("getSimpleDateFormat "+pattern+":"+locale);
    	String key=pattern+locale;
    	SimpleDateFormat sdf;
    	if (sdfCache.containsKey(key)) {
    		sdf=(SimpleDateFormat) sdfCache.get(key);
    	else {
        	sdf=new SimpleDateFormat(pattern, locale);
    	return sdf;

And later:
Instead of
	    DateFormat formatter = createFormatter(locale);
            // Apply pattern, if present
	    if (pattern != null) {
		try {
		    ((SimpleDateFormat) formatter).applyPattern(pattern);
		} catch (ClassCastException cce) {
		    formatter = new SimpleDateFormat(pattern, locale);

Something like
	    DateFormat formatter = getSimpleDateFormat (pattern, locale);	
Comment 2 Harm Jan Nijlunsing 2004-11-23 12:05:23 UTC
After making a prototype of the code mentioned earlier, I saw a tremendous 
increase in the performance; and no calendar.getInstance appeared in the 
However... Now we are experiencing locking issues with this method:

Fortunatly I don't seem to be alone anymore with this problem:

Is there any progress on this? (After all the above message was posted over 1 
year ago)
Comment 3 Harm Jan Nijlunsing 2004-11-23 12:53:31 UTC
Ah the above locking seems to be resolved in 1.0.6:
Comment 4 Henri Yandell 2006-12-13 15:29:57 UTC
The suggestion below of a static cache seems bad as SimpleDateFormat is not
thread safe. 

However we only access the formatter object in a very small location, so we
could change:

            if (tz != null) {
            formatted = formatter.format(value);


         synchronized(formatter) {
            if (tz != null) {
            formatted = formatter.format(value);

The current code does also access formatter when creating, but that's because
it's doing daft things in creation. The code below gets rid of that.

So this is fixable and needs a demonstrative test to be created. 
Comment 5 Henri Yandell 2006-12-13 15:47:36 UTC
As with 17700, the question of what to do with the cache over time exists.

In this case it seems unlikely that we would have an enormous number of patterns
being created; so I wouldn't expect the map to grow hugely.

One solution might be to implement a very basic pool - but that seems very
likely to lead to bugs while we get it right.
Comment 6 Henri Yandell 2007-02-07 17:33:08 UTC
SPI style plugin cache added for this (see attachment to issue
https://issues.apache.org/bugzilla/show_bug.cgi?id=31789 ).
Comment 7 Henri Yandell 2007-09-30 00:46:05 UTC
Created attachment 20900 [details]
Fix+Test patch

Attaching a fix and a test. The test fails because Cactus does not seem to set
the locale on the request. The default action then is to print date.toString().
Switching that to use the Locale.getDefault() shows that the code is working.

Probably have to just ditch the test and just go with the fix, along with a
sample app showing that things are okay.
Comment 8 Henri Yandell 2007-10-15 22:35:47 UTC
Created attachment 20987 [details]
Fix+More Tests

Adding a few more tests, though it is more of a proof and not a test.
Comment 9 Henri Yandell 2007-10-15 22:40:56 UTC
svn ci -m "Applying the fix and the tests from #32311 - LRUMap used as a caching
system to improve on performance"

Sending        src/org/apache/taglibs/standard/tag/common/fmt/FormatDateSupport.java
Adding         test/org/apache/taglibs/standard/tag/el/fmt
Adding         test/org/apache/taglibs/standard/tag/el/fmt/TestDateTag.java
Adding         test/web/org/apache/taglibs/standard/tag/el/fmt
Adding         test/web/org/apache/taglibs/standard/tag/el/fmt/TestDateTag.jsp
Transmitting file data ...
Committed revision 585044.