Merge change I42d17725 into eclair-mr2

* changes:
  Cache NumberFormat and DecimalFormatSymbols objects in a ThreadLocal, so they can be reused between multiple instances of Formatter on the same thread.  This speeds up my unscientific benchmark (a number of printouts involved in a debugging diagnostics output) by 3x, and should have a similar impact on anyone who uses String.format(), PrintWriter.format(), and the like.
diff --git a/libcore/luni/src/main/java/java/util/Formatter.java b/libcore/luni/src/main/java/java/util/Formatter.java
index 3d8b94e..9198886 100644
--- a/libcore/luni/src/main/java/java/util/Formatter.java
+++ b/libcore/luni/src/main/java/java/util/Formatter.java
@@ -38,6 +38,10 @@
 import java.text.DecimalFormatSymbols;
 import java.text.NumberFormat;
 
+// BEGIN android-added
+import org.apache.harmony.luni.util.LocaleCache;
+// END android-added
+
 /**
  * <p>The {@code Formatter} class is a String-formatting utility that is designed
  * to work like the {@code printf} function of the C programming language.
@@ -1173,14 +1177,18 @@
 
         private NumberFormat getNumberFormat() {
             if (null == numberFormat) {
-                numberFormat = NumberFormat.getInstance(locale);
+                // BEGIN android-changed
+                numberFormat = LocaleCache.getNumberFormat(locale);
+                // END android-changed
             }
             return numberFormat;
         }
 
         private DecimalFormatSymbols getDecimalFormatSymbols() {
             if (null == decimalFormatSymbols) {
-                decimalFormatSymbols = new DecimalFormatSymbols(locale);
+                // BEGIN android-changed
+                decimalFormatSymbols = LocaleCache.getDecimalFormatSymbols(locale);
+                // END android-changed
             }
             return decimalFormatSymbols;
         }
diff --git a/libcore/luni/src/main/java/org/apache/harmony/luni/util/LocaleCache.java b/libcore/luni/src/main/java/org/apache/harmony/luni/util/LocaleCache.java
new file mode 100644
index 0000000..c591faf
--- /dev/null
+++ b/libcore/luni/src/main/java/org/apache/harmony/luni/util/LocaleCache.java
@@ -0,0 +1,81 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package org.apache.harmony.luni.util;
+
+import java.text.NumberFormat;
+import java.text.DecimalFormatSymbols;
+import java.util.Locale;
+
+/**
+ * Manages a locale-specific thread-local cache of expensive locale-specific
+ * format objects.  The objects are discarded if the locale requested changes,
+ * or if heap space is exhausted.
+ */
+public class LocaleCache {
+
+    private static final ThreadLocalCache<LocaleCache> cache = new ThreadLocalCache<LocaleCache>();
+
+    private NumberFormat numberFormat = null;
+
+    private DecimalFormatSymbols decimalFormatSymbols = null;
+
+    private final Locale locale;
+
+    private LocaleCache(Locale locale) {
+        this.locale = locale;
+    }
+
+    /**
+     * Re-uses or creates a LocaleCache object for the specified Locale.
+     * LocaleCache objects are reused within a thread as long as they have
+     * the same Locale (which must not be null).
+     */
+    private static LocaleCache getLocaleCache(Locale locale) {
+        LocaleCache lc = cache.get();
+        if (lc == null || !lc.locale.equals(locale)) {
+            lc = new LocaleCache(locale);
+            cache.set(lc);
+        }
+        return lc;
+    }
+
+    /**
+     * Returns a NumberFormat object initialized with the specified
+     * Locale, re-using a previously returned object if possible.
+     */
+    public static NumberFormat getNumberFormat(Locale locale) {
+        LocaleCache lc = getLocaleCache(locale);
+        if (lc.numberFormat == null) {
+            lc.numberFormat = NumberFormat.getInstance(locale);
+        }
+        return lc.numberFormat;
+    }
+
+    /**
+     * Returns a DecimalFormatSymbols object initialized with the specified
+     * Locale, re-using a previously returned object if possible.
+     */
+    public static DecimalFormatSymbols getDecimalFormatSymbols(Locale locale) {
+        LocaleCache lc = getLocaleCache(locale);
+        if (lc.decimalFormatSymbols == null) {
+            lc.decimalFormatSymbols = new DecimalFormatSymbols(locale);
+        }
+        return lc.decimalFormatSymbols;
+    }
+
+}