Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8368328

CompactNumberFormat.clone does not produce independent instances

XMLWordPrintable

    • master
    • generic
    • generic

      A DESCRIPTION OF THE PROBLEM :
      When using instances from CompactNumberFormat.clone across threads, the instances interfere with each other because internal state is still shared.


      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      1. Save the attached code to CompactFormatCloneTest.java
      2. run with java CompactFormatCloneTest.java

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      No output
      ACTUAL -
      Output (varies per run)

      parseClone 2: expected 2 but got 5
      parseClone 7: expected 7 but got 9
      formatClone 4: exceptionFor input string: ".4E14E1"
      formatClone 6: exceptionFor input string: ".6E16E1"
      parseClone 8: expected 8 but got 5
      parseClone 3: expected 3 but got 1
      parseClone 4: expected 4 but got 1
      formatClone 3: exceptionFor input string: ".E0"
      formatClone 9: exceptionFor input string: ".E0"
      parseClone 5: expected 5 but got 1
      parseClone 0: expected 0 but got 1
      formatClone 2: exceptionFor input string: ".2E2E1"
      parseClone 9: expected 9 but got 1
      formatClone 7: exceptionFor input string: ".7E7E1"
      parseClone 6: expected 6 but got 1
      formatClone 8: exceptionFor input string: ".8E8E1"
      formatClone 5: exceptionFor input string: ".5E15E1"

      ---------- BEGIN SOURCE ----------
      import java.text.NumberFormat;
      import java.util.Locale;

      public class CompactFormatCloneTest {
          public static void main(String[] args) {

              // successful format loop does not use clone()
              for (int i = 0; i < 10; i++) {
                  // give each thread a fresh copy of the format
                  NumberFormat instance = createFormat();
                  new Thread(new FormatTest(i, instance), "freshFormat " + i).start();
              }

              NumberFormat originalInstance = createFormat();

              // unsuccessful format loop using clone()
              for (int i = 0; i < 10; i++) {
                  // give each thread a clone of the original
                  NumberFormat instance = (NumberFormat) originalInstance.clone();
                  new Thread(new FormatTest(i, instance), "formatClone " + i).start();
              }

              // unsuccessful parse loop using clone()
              for (int i = 0; i < 10; i++) {
                  // give each thread a clone of the original
                  NumberFormat instance = (NumberFormat) originalInstance.clone();
                  new Thread(new ParseTest(i, instance), "parseClone " + i).start();
              }

          }


          public record FormatTest(int value, NumberFormat format) implements Runnable {

              @Override
              public void run() {
                  String expected = String.valueOf(value);

                  for (int i = 0; i < 1000; i++) {
                      try {
                          String result = format.format(value);
                          if (!result.equals(expected)) {
                              System.out.println(Thread.currentThread().getName() + ": expected " + expected + " but got " + result);
                              break;
                          }
                      } catch (Exception e) {
                          System.out.println(Thread.currentThread().getName() + ": exception" + e.getMessage());
                          break;
                      }
                  }
              }
          }

          public record ParseTest(int value, NumberFormat format) implements Runnable {

              @Override
              public void run() {
                  String str = String.valueOf(value);

                  for (int i = 0; i < 1000; i++) {
                      try {
                          int result = format.parse(str).intValue();
                          if (result != value) {
                              System.out.println(Thread.currentThread().getName() + ": expected " + value + " but got " + result);
                              break;
                          }
                      } catch (Exception e) {
                          System.out.println(Thread.currentThread().getName() + ": exception" + e.getMessage());
                          break;
                      }
                  }
              }
          }

          private static NumberFormat createFormat() {
              return NumberFormat.getCompactNumberInstance(Locale.US, NumberFormat.Style.SHORT);
          }
      }
      ---------- END SOURCE ----------

            naoto Naoto Sato
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            6 Start watching this issue

              Created:
              Updated:
              Resolved: