惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Google DeepMind News
Google DeepMind News
博客园 - 司徒正美
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
V
V2EX
博客园_首页
量子位
博客园 - 三生石上(FineUI控件)
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
腾讯CDC
T
The Blog of Author Tim Ferriss
博客园 - 聂微东
V
Visual Studio Blog
J
Java Code Geeks
宝玉的分享
宝玉的分享
爱范儿
爱范儿
MongoDB | Blog
MongoDB | Blog
D
Docker
大猫的无限游戏
大猫的无限游戏
Y
Y Combinator Blog
H
Help Net Security
罗磊的独立博客
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Blog — PlanetScale
Blog — PlanetScale

博客园 - 如.若

Linux系统负载过高问题排查 Git 配置 ssh-key 免密登录 cron表达式详解 Spring Boot 使用 EnvironmentPostProcessor 接口实现加载外部配置文件 AdoptOpenJDK(JAVA环境)安装 JVM优化之 -Xss -Xms -Xmx -Xmn 参数设置 JAVA 多线程基础 SQL 存储过程游标应用 SQL 语句实现查询子父节点 Spring ClassPathResource加载资源文件详解 浅谈web项目读取classpath路径下面的文件 SpringBoot+SpringSecurity+SpringSession实现一个前后端分离的权限管理系统 Spring Security 中 CSRF 防御源码解析 Redis 持久化 SpringBoot 如何防御 CSRF 攻击 数据库建模-规范 接口的幂等性怎么设计? TOP命令结果分析 Redis配置参数详解
SimpleDateFormat线程不安全的5种解决方案
如.若 · 2021-05-18 · via 博客园 - 如.若

1.什么是线程不安全?

线程不安全也叫非线程安全,是指多线程执行中,程序的执行结果和预期的结果不符的情况就叫着线程不安全。

线程不安全的代码

SimpleDateFormat 就是一个典型的线程不安全事例,接下来我们动手来实现一下。首先我们先创建 10 个线程来格式化时间,时间格式化每次传递的待格式化时间都是不同的,所以程序如果正确执行将会打印 10 个不同的值,接下来我们来看具体的代码实现:

import java.text.SimpleDateFormat; 
import java.util.Date; 
import java.util.concurrent.ExecutorService; 
import java.util.concurrent.Executors; 
 
public class SimpleDateFormatExample { 
    // 创建 SimpleDateFormat 对象 
    private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("mm:ss"); 
 
    public static void main(String[] args) { 
        // 创建线程池 
        ExecutorService threadPool = Executors.newFixedThreadPool(10); 
        // 执行 10 次时间格式化 
        for (int i = 0; i < 10; i++) { 
            int finalI = i; 
            // 线程池执行任务 
            threadPool.execute(new Runnable() { 
                @Override 
                public void run() { 
                    // 创建时间对象 
                    Date date = new Date(finalI * 1000); 
                    // 执行时间格式化并打印结果 
                    System.out.println(simpleDateFormat.format(date)); 
                } 
            }); 
        } 
    } 
} 

我们预期的正确结果是这样的(10 次打印的值都不同):

然而,以上程序的运行结果却是这样的:

从上述结果可以看出,当在多线程中使用 SimpleDateFormat 进行时间格式化是线程不安全的。

2.解决方案

SimpleDateFormat 线程不安全的解决方案总共包含以下 5 种:

  1. 将 SimpleDateFormat 定义为局部变量;
  2. 使用 synchronized 加锁执行;
  3. 使用 Lock 加锁执行(和解决方案 2 类似);
  4. 使用 ThreadLocal;
  5. 使用 JDK 8 中提供的 DateTimeFormat。

接下来我们分别来看每种解决方案的具体实现。

① SimpleDateFormat改为局部变量

将 SimpleDateFormat 定义为局部变量时,因为每个线程都是独享 SimpleDateFormat 对象的,相当于将多线程程序变成“单线程”程序了,所以不会有线程不安全的问题,具体实现代码如下: