You are viewing a plain text version of this content. The canonical link for it is here.
Posted to fop-commits@xmlgraphics.apache.org by je...@apache.org on 2008/06/18 16:07:28 UTC

svn commit: r669173 - in /xmlgraphics/fop/branches/fop-0_95: src/java/org/apache/fop/fonts/MultiByteFont.java src/java/org/apache/fop/pdf/PDFNumber.java status.xml

Author: jeremias
Date: Wed Jun 18 07:07:27 2008
New Revision: 669173

URL: http://svn.apache.org/viewvc?rev=669173&view=rev
Log:
Bugzilla #44887:
Fixed potential multi-threading problem concerning the use of DecimalFormat.

Results from performance measurements in a separate test (operation repeated 100'000 times, exemplary):
shared static variable: ~220ms (old choice, problematic!)
always create new instance: ~480ms
ThreadLocal: ~220ms (new choice)

Modified:
    xmlgraphics/fop/branches/fop-0_95/src/java/org/apache/fop/fonts/MultiByteFont.java
    xmlgraphics/fop/branches/fop-0_95/src/java/org/apache/fop/pdf/PDFNumber.java
    xmlgraphics/fop/branches/fop-0_95/status.xml

Modified: xmlgraphics/fop/branches/fop-0_95/src/java/org/apache/fop/fonts/MultiByteFont.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/fop-0_95/src/java/org/apache/fop/fonts/MultiByteFont.java?rev=669173&r1=669172&r2=669173&view=diff
==============================================================================
--- xmlgraphics/fop/branches/fop-0_95/src/java/org/apache/fop/fonts/MultiByteFont.java (original)
+++ xmlgraphics/fop/branches/fop-0_95/src/java/org/apache/fop/fonts/MultiByteFont.java Wed Jun 18 07:07:27 2008
@@ -29,7 +29,6 @@
 public class MultiByteFont extends CIDFont {
 
     private static int uniqueCounter = -1;
-    private static final DecimalFormat COUNTER_FORMAT = new DecimalFormat("00000");
 
     private String ttcName = null;
     private String encoding = "Identity-H";
@@ -63,7 +62,8 @@
                 uniqueCounter = 0; //We need maximum 5 character then we start again
             }
         }
-        String cntString = COUNTER_FORMAT.format(uniqueCounter);
+        DecimalFormat counterFormat = new DecimalFormat("00000");
+        String cntString = counterFormat.format(uniqueCounter);
         
         //Subset prefix as described in chapter 5.5.3 of PDF 1.4
         StringBuffer sb = new StringBuffer("E");

Modified: xmlgraphics/fop/branches/fop-0_95/src/java/org/apache/fop/pdf/PDFNumber.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/fop-0_95/src/java/org/apache/fop/pdf/PDFNumber.java?rev=669173&r1=669172&r2=669173&view=diff
==============================================================================
--- xmlgraphics/fop/branches/fop-0_95/src/java/org/apache/fop/pdf/PDFNumber.java (original)
+++ xmlgraphics/fop/branches/fop-0_95/src/java/org/apache/fop/pdf/PDFNumber.java Wed Jun 18 07:07:27 2008
@@ -67,10 +67,32 @@
         return doubleOut(doubleDown, 6);
     }
 
-    // Static cache. Possible concurrency implications. See comment in doubleOut(double, int).
-    private static DecimalFormat[] decimalFormatCache = new DecimalFormat[17];
-    
     private static final String BASE_FORMAT = "0.################";
+
+    private static class DecimalFormatThreadLocal extends ThreadLocal {
+        
+        private int dec;
+        
+        public DecimalFormatThreadLocal(int dec) {
+            this.dec = dec;
+        }
+        
+        protected synchronized Object initialValue() {
+            String s = "0";
+            if (dec > 0) {
+                s = BASE_FORMAT.substring(0, dec + 2);
+            }
+            DecimalFormat df = new DecimalFormat(s, new DecimalFormatSymbols(Locale.US));
+            return df;
+        }
+    };
+    //DecimalFormat is not thread-safe!
+    private static final ThreadLocal[] DECIMAL_FORMAT_CACHE = new DecimalFormatThreadLocal[17];
+    static {
+        for (int i = 0, c = DECIMAL_FORMAT_CACHE.length; i < c; i++) {
+            DECIMAL_FORMAT_CACHE[i] = new DecimalFormatThreadLocal(i);
+        }
+    }
     
     /**
      * Output a double value to a string suitable for PDF.
@@ -82,29 +104,15 @@
      * @return the value as a string
      */
     public static String doubleOut(double doubleDown, int dec) {
-        if (dec < 0 || dec >= decimalFormatCache.length) {
+        if (dec < 0 || dec >= DECIMAL_FORMAT_CACHE.length) {
             throw new IllegalArgumentException("Parameter dec must be between 1 and " 
-                    + (decimalFormatCache.length + 1));
+                    + (DECIMAL_FORMAT_CACHE.length + 1));
         }
-        if (decimalFormatCache[dec] == null) {
-            //We don't care about the rare case where a DecimalFormat might be replaced in
-            //a multi-threaded environment, so we don't synchronize the access to the static
-            //array (mainly for performance reasons). After all, the DecimalFormat instances
-            //read-only objects so it doesn't matter which instance is used as long as one
-            //is available.
-            String s = "0";
-            if (dec > 0) {
-                s = BASE_FORMAT.substring(0, dec + 2);
-            }
-            DecimalFormat df = new DecimalFormat(s, new DecimalFormatSymbols(Locale.US));
-            decimalFormatCache[dec] = df;
-        }
-        return decimalFormatCache[dec].format(doubleDown);
+        DecimalFormat df = (DecimalFormat)DECIMAL_FORMAT_CACHE[dec].get();
+        return df.format(doubleDown);
     }
 
-    /**
-     * {@inheritDoc}
-     */
+    /** {@inheritDoc} */
     protected String toPDFString() {
         if (getNumber() == null) {
             throw new IllegalArgumentException(

Modified: xmlgraphics/fop/branches/fop-0_95/status.xml
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/fop-0_95/status.xml?rev=669173&r1=669172&r2=669173&view=diff
==============================================================================
--- xmlgraphics/fop/branches/fop-0_95/status.xml (original)
+++ xmlgraphics/fop/branches/fop-0_95/status.xml Wed Jun 18 07:07:27 2008
@@ -60,8 +60,11 @@
       -->
     <!--/release-->
     <release version="0.95" date="TBD">
+      <action context="Code" dev="JM" type="fix" fixes-bug="44887">
+        Fixed potential multi-threading problem concerning the use of DecimalFormat.
+      </action>
       <action context="Layout" dev="JM" type="fix" fixes-bug="44412">
-        Regression bugfix: Multiple collapsable breaks don't cause empty pages anymore.
+        Regression bugfix: Multiple collapsible breaks don't cause empty pages anymore.
       </action>
       <action context="Renderers" dev="JM" type="fix">
         Fixed resolution handling inside AWT preview dialog.



---------------------------------------------------------------------
To unsubscribe, e-mail: fop-commits-unsubscribe@xmlgraphics.apache.org
For additional commands, e-mail: fop-commits-help@xmlgraphics.apache.org