多线程避免使用SimpleDateFormat及替代方案
先来看一个多线程下使用例子,看到运行结果会出现异常:
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() { @Override public 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); } } }); } } }
运行结果:
在并发环境下使用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,整个转换过程都不需要考虑线程安全的问题。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 字符编码:从基础到乱码解决