CompactNumberFormat.clone does not produce independent instances

XMLWordPrintable

    • b18
    • 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 ----------

              Assignee:
              Naoto Sato
              Reporter:
              Webbug Group
              Votes:
              0 Vote for this issue
              Watchers:
              7 Start watching this issue

                Created:
                Updated:
                Resolved: