您的位置:首页技术文章
文章详情页

Java在并发环境中SimpleDateFormat多种解决方案

【字号: 日期:2022-08-29 16:10:08浏览:10作者:猪猪

先来看一个多线程下使用例子,看到运行结果会出现异常:

import java.text.DateFormat;import java.text.SimpleDateFormat;import java.util.Date;import java.util.Random;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors; public class SimpleDateFormateTest { public static void main(String[] args) { final DateFormat df = new SimpleDateFormat('yyyyMMdd,HHmmss'); ExecutorService ts = Executors.newFixedThreadPool(100); for (;;) { ts.execute(new Runnable() { @Overridepublic void run() { try { //生成随机数,格式化日期 String format = df.format(new Date(Math.abs(new Random().nextLong()))); System.out.println(format); } catch (Exception e) { e.printStackTrace(); System.exit(1); }} }); } } }

运行结果:

Java在并发环境中SimpleDateFormat多种解决方案

在并发环境下使用SimpleDateFormat,正常的打开放式如下:

为了能够在多线程环境下使用SimpleDateFormat,有这六种方法:

方法一

在需要执行格式化的地方都新建SimpleDateFormat实例,使用局部变量来存放SimpleDateFormat实例

public static String formatDate(Date date)throws ParseException{ SimpleDateFormat sdf = new SimpleDateFormat('yyyy-MM-dd HH:mm:ss'); return sdf.format(date);}

这种方法可能会导致短期内创建大量的SimpleDateFormat实例,如解析一个excel表格里的字符串日期。

方法二

为了避免创建大量的SimpleDateFormat实例,往往会考虑把SimpleDateFormat实例设为静态成员变量,共享SimpleDateFormat对象。这种情况下就得对SimpleDateFormat添加同步。

private static SimpleDateFormat sdf = new SimpleDateFormat('yyyy-MM-dd HH:mm:ss');public static String formatDate(Date date)throws ParseException{ synchronized(sdf){ return sdf.format(date); } }

这种方法的缺点也很明显,就是在高并发的环境下会导致解析被阻塞。

方法三 

方法加同步锁synchronized,在同一时刻,只有一个线程可以执行类中的某个方法。

缺点:性能较差,每次都要等待锁释放后其他线程才能进入。

方案四 使用第三方包

这个我有尝试cn.hutool和common-lang3提供的FastDateFormat最后的结果其实并不满意,因为这两个包都没能帮助我检查非正常时间,比如2018-07-32这种日期也被认为是正确的时期格式了

方法五(推荐)

要在高并发环境下能有比较好的体验,可以使用ThreadLocal来限制SimpleDateFormat只能在线程内共享,这样就避免了多线程导致的线程安全问题。

private static ThreadLocal<DateFormat> threadLocal = new ThreadLocal<DateFormat>() { @Override protected DateFormat initialValue() { return new SimpleDateFormat('yyyy-MM-dd HH:mm:ss'); }};public static String format(Date date) { return threadLocal.get().format(date);}

方案六 DateTimeFormatter使用

Java8提供了新的日期时间API,其中包括用于日期时间格式化的DateTimeFormatter,它与SimpleDateFormat的有什么区别呢?

问题解决

两者最大的区别是,Java8的DateTimeFormatter也是线程安全的,而SimpleDateFormat并不是线程安全。

解析日期

String dateStr= '2016年10月25日'; DateTimeFormatter formatter = DateTimeFormatter.ofPattern('yyyy年MM月dd日'); LocalDate date= LocalDate.parse(dateStr, formatter);

日期转换为字符串

LocalDateTime now = LocalDateTime.now(); DateTimeFormatter format = DateTimeFormatter.ofPattern('yyyy年MM月dd日 hh:mm a'); String nowStr = now .format(format);

由DateTimeFormatter的静态方法ofPattern()构建日期格式,LocalDateTime和LocalDate等一些表示日期或时间的类使用parse和format方法把日期和字符串做转换。

使用新的API,整个转换过程都不需要考虑线程安全的问题。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持好吧啦网。

标签: Java
相关文章: