NumberFormatException while parsing date with SimpleDateFormat.parse()

前端 未结 7 1323
我寻月下人不归
我寻月下人不归 2020-12-08 07:11

Have a function that creates a time-only Date object. (why this is required is a long story which is irrelevant in this context but I need to compare to some stuff in XML wo

7条回答
  •  广开言路
    2020-12-08 07:54

    SimpleDateFormat is not thread safe. the following program will reproduce NumberFormatException while parsing string represented date to date object.

    public class MaintainEqualThreadsPatallel {
        static int parallelCount = 20;
        public static void main(String[] args) throws Exception {
            ExecutorService executorPool = Executors.newFixedThreadPool(parallelCount);
    
            int numberOfThreads = 150; // Total thread count = 150*2= 300.
            List> futureReturns = new LinkedList>();
            for (int i = 0; i < numberOfThreads; i++) {
                int uniqueRandomValues = uniqueRandomValues(1, 10);
    
                // Callable Thread - call()
                Future submit = executorPool.submit( new WorkerCallable(uniqueRandomValues) );
                futureReturns.add(submit);
    
                // Runnable Thread - run()
                executorPool.execute( new WorkerThread(uniqueRandomValues) );
            }
    
            // WorkerCallable: Blocking main thread until task completes.
            waitTillThreadsCompleteWork(futureReturns);
            // Terminate Pool threads in-order to terminate main thread
            executorPool.shutdown();
        }
        private static final SimpleDateFormat sdf = new SimpleDateFormat("dd-MMM-yyyy HH:mm:ss");
        public static Date numberFormatEx(Date date) throws ParseException { // synchronized
            String dateStr = sdf.format(date);
            Date dateParsed = sdf.parse(dateStr); // NumberFormatException: For input string: "186E.2186E2"
            System.out.println("Date :"+ dateParsed);
            return dateParsed;
        }
    
        protected void loopFunction(int repeatCount) {
            String threadName = Thread.currentThread().getName();
            System.out.println(threadName +":START");
            for (int i = 1; i <= repeatCount; i++) {
                try {
                    System.out.println(threadName +":"+ i);
                    sleepThread(100);
    
                    numberFormatEx(new Date());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            System.out.println(threadName +":END");
        }
    
        public static void waitTillThreadsCompleteWork(List> futureReturns) throws Exception {
            for (Future future : futureReturns) {
                int threadReturnVal = (int) future.get();
                System.out.println("Future Response : "+threadReturnVal);
            }
        }
    
        public static int uniqueRandomValues(int min, int max) {
            int nextInt = ThreadLocalRandom.current().nextInt(min, max);
            System.out.println("Random Vlaue : "+nextInt);
            return nextInt;
        }
        public void sleepThread(long mills) {
            try {
                Thread.sleep(mills);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    class WorkerThread extends MaintainEqualThreadsPatallel implements Runnable {
        int randomValue = 0;
        public WorkerThread(int randomValue) {
            this.randomValue = randomValue;
        }
    
        @Override
        public void run() {
            // As separate stack run() function doesn't accepts parameters, pass to constructor.
            loopFunction(randomValue);
        }
    }
    class WorkerCallable extends MaintainEqualThreadsPatallel implements Callable {
        int randomValue = 0;
        public WorkerCallable(int randomValue) {
            this.randomValue = randomValue;
        }
    
        public Object call() {
            // As separate stack run() function doesn't accepts parameters, pass to constructor.
            loopFunction(randomValue);
            return randomValue;
        }
    }
    
    
    

    NumberFormatException with different messages:

    java.lang.NumberFormatException: multiple points
    java.lang.NumberFormatException: For input string: ""
    java.lang.NumberFormatException: For input string: "186E.2"
    java.lang.NumberFormatException: For input string: "186E.2186E2"
    java.lang.NumberFormatException: For input string: "22200222E.222002224EE4"
    
    java.lang.NumberFormatException: For input string: "22200222E.222002224EE44"
        at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:2043)
        at sun.misc.FloatingDecimal.parseDouble(FloatingDecimal.java:110)
        at java.lang.Double.parseDouble(Double.java:538)
        at java.text.DigitList.getDouble(DigitList.java:169)
        at java.text.DecimalFormat.parse(DecimalFormat.java:2056)
        at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1869)
        at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1514)
        at java.text.DateFormat.parse(DateFormat.java:364)
    

    In Multi-Threading/Web Application with Multi-Requests concept parse function leads to NumberFormatException which can be handled using synchronized block.


    To overcome NumberFormatException on parse() function use any of the following scenarios.

    1. Separate Object: Every request/thread works on its own object.
    public static Date numberFormatEx(Date date) throws ParseException {
        SimpleDateFormat ObjInstance = new SimpleDateFormat("dd-MMM-yyyy HH:mm:ss");
        String dateStr = ObjInstance.format(date);
        Date dateParsed = ObjInstance.parse(dateStr);
        System.out.println("Date :"+ dateParsed);
        return dateParsed;
    }
    

    Unnecessary creating reusable object for each thread.

    1. Static Object synchronized block: Every request/thread shares the common object to perform operation. As multiple threads share same object at same time then the object data gets clear/overrride ""/"186E.2186E2" at some point and leads to error.
    static SimpleDateFormat objStatic = new SimpleDateFormat("dd-MMM-yyyy HH:mm:ss");
    public static synchronized Date numberFormatEx(Date date) throws ParseException {
        String dateStr = objStatic.format(date);
        Date dateParsed = objStatic.parse(dateStr); // NumberFormatException: For input string: "186E.2186E2"
        System.out.println("Date :"+ dateParsed);
        return dateParsed;
    }
    

    NOTE: In case of Memory management it better to use synchronized block with static object which is reusable.

    提交回复
    热议问题