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