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

  • 相关阅读:
    解决pip3的ImportError: cannot import name 'main'
    linux 安装Python3.6
    Linux安装redis和部署
    redis密码管理
    CentOS7使用firewalld打开关闭防火墙与端口
    scrapy 从Windwos平台移植到 Linux平台之实操
    Linux 环境下安装Maven
    解决:安装Jenkins时web界面出现该jenkins实例似乎已离线
    持续集成工具Jenkins结合SVN的安装和使用
    Linux下的SVN服务器搭建
  • 原文地址:https://www.cnblogs.com/iuyy/p/14379067.html
Copyright © 2011-2022 走看看