标题: Simple Date Format类到底为啥不是线程安全的? [打印本页] 作者: 熊熊出没 时间: 2023-6-5 12:33 标题: Simple Date Format类到底为啥不是线程安全的?
摘要:我们就一起看下在高并发下Simple Date Format类为何会出现安全问题,以及如何解决Simple Date Format类的安全问题。
本文分享自华为云社区《【高并发】SimpleDateFormat类到底为啥不是线程安全的?》,作者:冰 河。 首先问下大家:你使用的Simple Date Format类还安全吗?为什么说Simple Date Format 类不是线程安全的?带着问题从本文中寻求答案。
提起Simple Date Format 类,想必做过Java开发的童鞋都不会感到陌生。没错,它就是Java中提供的日期时间的转化类。这里,为什么说Simple Date Format 类有线程安全问题呢?有些小伙伴可能会提出疑问:我们生产环境上一直在使用Simple Date Format 类来解析和格式化日期和时间类型的数据,一直都没有问题啊!我的回答是:没错,那是因为你们的系统达不到Simple Date Format 类出现问题的并发量,也就是说你们的系统没啥负载!
接下来,我们就一起看下在高并发下Simple Date Format 类为何会出现安全问题,以及如何解决 Simple Date Format 类的安全问题。
重现 Simple Date Format类的线程安全问题
为了重现Simple Date Format类的线程安全问题,一种比较简单的方式就是使用线程池结合Java并发包中的Count Down Latch类和Semaphore类来重现线程安全问题。 有关Count Down Latch 类和Semaphore类的具体用法和底层原理与源码解析在【高并发专题】后文会深度分析。这里,大家只需要知道 Count Down Latch 类可以使一个线程等待其他线程各自执行完毕后再执行。而Semaphore类可以理解为一个计数信号量,必须由获取它的线程释放,经常用来限制访问某些资源的线程数量,例如限流等。
好了,先来看下重现Simple Date Format 类的线程安全问题的代码,如下所示。
package io.binghe.concurrent.lab06;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
/**
* @author binghe
* @version 1.0.0
* @description 测试SimpleDateFormat的线程不安全问题
*/
public class SimpleDateFormatTest01 {
//执行总次数
private static final int EXECUTE_COUNT = 1000;
//同时运行的线程数量
private static final int THREAD_COUNT = 20;
//SimpleDateFormat对象
private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
public static void main(String[] args) throws InterruptedException {
final Semaphore semaphore = new Semaphore(THREAD_COUNT);
final CountDownLatch countDownLatch = new CountDownLatch(EXECUTE_COUNT);
at java.text.DigitList.getLong(DigitList.java:195)
at java.text.DecimalFormat.parse(DecimalFormat.java:2084)
at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:2162)
at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1514)
at java.text.DateFormat.parse(DateFormat.java:364)
at io.binghe.concurrent.lab06.SimpleDateFormatTest01.lambda$main$0(SimpleDateFormatTest01.java:47)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
java.lang.NumberFormatException: For input string: ""
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Long.parseLong(Long.java:601)
at java.lang.Long.parseLong(Long.java:631)
at java.text.DigitList.getLong(DigitList.java:195)
at java.text.DecimalFormat.parse(DecimalFormat.java:2084)
at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1869)
at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1514)
at java.text.DateFormat.parse(DateFormat.java:364)
Process finished with exit code 1
复制代码
说明,在高并发下使用Simple Date Format 类格式化日期时抛出了异常,Simple Date Forma t类不是线程安全的!!!
接下来,我们就看下,Simple Date Format 类为何不是线程安全的。
Simple Date Format 类为何不是线程安全的?
那么,接下来,我们就一起来看看真正引起Simple Date Format类线程不安全的根本原因。
通过查看Simple Date Format类的源码,我们得知:Simple Date Format是继承自Date Format类,Date Format类中维护了一个全局的Calendar变量,如下所示。
/**
* The {@link Calendar} instance used for calculating the date-time fields
* and the instant of time. This field is used for both formatting and
* parsing.
*
* <p>Subclasses should initialize this field to a {@link Calendar}
* appropriate for the {@link Locale} associated with this