zoukankan      html  css  js  c++  java
  • SimpleDateFormat线程安全性测试与解决方案

    Date formats are not synchronized.
    It is recommended to create separate format instances for each thread.
    If multiple threads access a format concurrently, it must be synchronized externally.
    SimpleDateFormat不是一个线程安全的类,在多线程环境中调用相关方法,将会引发线程安全问题,本节演示其线程安全问题,并通过ThreadLocal解决其线程安全问题!
    线程安全问题的演示:
    package simpledateformat;
    
    import java.text.ParseException;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    
    public class SimpleDateFormatTask implements Runnable {
    
        private ThreadLocal<SimpleDateFormat> threadLocal;
        private SimpleDateFormat simpleDateFormat;
        private String dateString;
    
        public SimpleDateFormatTask(SimpleDateFormat simpleDateFormat, String dateString) {
            this.simpleDateFormat = simpleDateFormat;
            this.dateString = dateString;
        }
    
        public SimpleDateFormatTask(ThreadLocal<SimpleDateFormat> threadLocal, String dateString) {
            this.threadLocal = threadLocal;
            this.dateString = dateString;
        }
    
        @Override
        public void run() {
            try {
                if (simpleDateFormat == null) {
                    simpleDateFormat = threadLocal.get();
                }
                Date date = simpleDateFormat.parse(dateString);
                String newDate = simpleDateFormat.format(date);
                if (!newDate.equals(dateString)) {
                    System.out.println("An error occurred in SimpleDateFormat!");
                }
            } catch (Exception e) {
                System.out.println("An exception occurred in SimpleDateFormat!");
            }
        }
    }
    
    class Main {
        private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        private static ThreadLocal<SimpleDateFormat> threadLocal = new ThreadLocal<SimpleDateFormat>() {
            @Override
            protected SimpleDateFormat initialValue() {
                return new SimpleDateFormat("yyyy-MM-dd");
            }
        };
    
        public static void main(String[] args) {
            String[] dateStringArray = new String[]{"2021-02-01", "2021-02-02", "2021-02-03", "2021-02-04", "2021-02-05"};
            Thread[] threads = new Thread[dateStringArray.length];
    
            for (int i = 0; i < dateStringArray.length; i++) {
                threads[i] = new Thread(new SimpleDateFormatTask(simpleDateFormat,dateStringArray[i]));
                //threads[i] = new Thread(new SimpleDateFormatTask(threadLocal, dateStringArray[i]));
            }
    
            for (int i = 0; i < dateStringArray.length; i++) {
                threads[i].start();
            }
        }
    }

    通过ThreadLocal解决其线程安全问题:

    package simpledateformat;
    
    import java.text.ParseException;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    
    public class SimpleDateFormatTask implements Runnable {
    
        private ThreadLocal<SimpleDateFormat> threadLocal;
        private SimpleDateFormat simpleDateFormat;
        private String dateString;
    
        public SimpleDateFormatTask(SimpleDateFormat simpleDateFormat, String dateString) {
            this.simpleDateFormat = simpleDateFormat;
            this.dateString = dateString;
        }
    
        public SimpleDateFormatTask(ThreadLocal<SimpleDateFormat> threadLocal, String dateString) {
            this.threadLocal = threadLocal;
            this.dateString = dateString;
        }
    
        @Override
        public void run() {
            try {
                if (simpleDateFormat == null) {
                    simpleDateFormat = threadLocal.get();
                }
                Date date = simpleDateFormat.parse(dateString);
                String newDate = simpleDateFormat.format(date);
                if (!newDate.equals(dateString)) {
                    System.out.println("An error occurred in SimpleDateFormat!");
                }
            } catch (Exception e) {
                System.out.println("An exception occurred in SimpleDateFormat!");
            }
        }
    }
    
    class Main0 {
        private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        private static ThreadLocal<SimpleDateFormat> threadLocal = new ThreadLocal<SimpleDateFormat>() {
            @Override
            protected SimpleDateFormat initialValue() {
                return new SimpleDateFormat("yyyy-MM-dd");
            }
        };
    
        public static void main(String[] args) {
            String[] dateStringArray = new String[]{"2021-02-01", "2021-02-02", "2021-02-03", "2021-02-04", "2021-02-05"};
            Thread[] threads = new Thread[dateStringArray.length];
    
            for (int i = 0; i < dateStringArray.length; i++) {
                //threads[i] = new Thread(new SimpleDateFormatTask(simpleDateFormat,dateStringArray[i]));
                threads[i] = new Thread(new SimpleDateFormatTask(threadLocal, dateStringArray[i]));
            }
    
            for (int i = 0; i < dateStringArray.length; i++) {
                threads[i].start();
            }
        }
    }

    补充:

    ThreadLocal类提供线程局部变量。 这些变量与普通变量不同,每个线程访问该变量时候都有其自己的独立初始化的变量副本。

    public class ThreadLocal<T> {
      
        protected T initialValue() {
            return null;
        }
       
        ...    
        
    }

    initialValue()方法返回此线程局部变量的当前线程的“初始值”。

    除非线程先前调用了set()方法,否则线程将在第一次使用get()方法访问该变量时调用此方法,在这种情况下,initialValue()方法将不会被调用。

    通常,每个线程最多调用一次此方法,但是在随后调用remove()之后再调用get()方法的情况下,可以再次调用此方法。

    默认实现仅返回null;。

    如果程序员希望线程局部变量的初始值不是null,则必须将ThreadLocal子类化,并重写此方法。通常,将使用匿名内部类的方法子类化。

    package simpledateformat;
    
    
    public class ThreadLocalTest {
        private static ThreadLocal<String> threadLocal = new ThreadLocal<String>() {
            @Override
            protected String initialValue() {
                return new String("Hello,ThreadLocal!");
            }
        };
    
        public static void main(String[] args) {
            Thread thread1 = new Thread(()->{
                System.out.println(System.identityHashCode(threadLocal.get()));
                threadLocal.remove();
            });
            Thread thread2 = new Thread(()->{
                System.out.println(System.identityHashCode(threadLocal.get()));
                threadLocal.remove();
            });
            thread1.start();
            thread2.start();
        }
    }

    更多内容:https://www.cnblogs.com/iuyy/p/13518177.html

  • 相关阅读:
    现代软件工程 第一章 概论 第3题——韩婧
    现代软件工程 第一章 概论 第2题——韩婧
    小组成员邓琨、白文俊、张星星、韩婧
    UVa 10892 LCM的个数 (GCD和LCM 质因数分解)
    UVa 10780 幂和阶乘 求n!中某个因子的个数
    UVa 11859 除法游戏(Nim游戏,质因子)
    Codeforces 703C Chris and Road 二分、思考
    Codeforces 703D Mishka and Interesting sum 树状数组
    hdu 5795 A Simple Nim SG函数(多校)
    hdu 5793 A Boring Question 推公式(多校)
  • 原文地址:https://www.cnblogs.com/iuyy/p/14379067.html
Copyright © 2011-2022 走看看