首页 > 其他分享 >【多线程】高并发之——SimpleDateFormat类的线程安全问题和解决方案

【多线程】高并发之——SimpleDateFormat类的线程安全问题和解决方案

时间:2023-02-21 18:44:06浏览次数:54  
标签:static simpleDateFormat private SimpleDateFormat ThreadLocal 线程 new 多线程

关于SimpleDateFormat

熟悉Java的同学知道这个类是线程不安全的,但究竟是怎样不安全法,什么原因产生的线程不安全?估计未必全部人都能够答得上来(我也不能,emmmm)


呃,想更好地了解关于 SimpleDateFormat 这个工具类的线程不安全的原因,推荐一位大佬的博客,请参考:高并发之——SimpleDateFormat类的线程安全问题和解决方案


正文

1、SimpleDateFormat 线程不安全的原因

请参考上述博文

2、解决方案

解决方案是有很多的

  • 把 SimpleDateFormat 放到方法里面(不太好)
  • 加 synchronized(不太好)
  • 加 lock (不太好)
  • 使用threadLocal (推荐)
  • 使用 DateTimeFormatter (推荐)
  • 使用joda-time方式(需要引入新依赖,看情况决定使用)

3、列一些demo代码

是为自己记得,参考的博文解释得更清楚些

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Semaphore;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;


public class SimpleDateFormatFix02 {

    //执行总次数
    private static final int EXECUTE_COUNT = 1000;
    //同时运行的线程数量
    private static final int THREAD_COUNT = 20;

    private static final String DATE_FORMAT = "yyyy-MM-dd";

    private static ThreadLocal<SimpleDateFormat> threadLocal = ThreadLocal.withInitial(() -> new SimpleDateFormat(DATE_FORMAT));

    // ThreadLocal的另外一种写法
    private static ThreadLocal<SimpleDateFormat> threadLocal2 = new ThreadLocal();
    private static SimpleDateFormat getDataFormat(){
        SimpleDateFormat simpleDateFormat = threadLocal2.get();
        if(null == simpleDateFormat){
            simpleDateFormat = new SimpleDateFormat(DATE_FORMAT);
            threadLocal2.set(simpleDateFormat);
        }
        return simpleDateFormat;
    }
    // end


    public static void main(String[] args) throws InterruptedException {
        final Semaphore semaphore = new Semaphore(THREAD_COUNT);
        final CountDownLatch countDownLatch = new CountDownLatch(EXECUTE_COUNT);

        ThreadPoolExecutor executor = new ThreadPoolExecutor(THREAD_COUNT, THREAD_COUNT, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<>(1000));
        for (int i = 0; i < EXECUTE_COUNT; i++) {
            executor.execute(() -> {
                try {
                    semaphore.acquire();
                    try {
                        threadLocal.get().parse("2022-01-01");
                    } catch (ParseException e) {
                        e.printStackTrace();
                        System.out.println("转换失败");
                        System.exit(1);
                    } catch (NumberFormatException e) {
                        e.printStackTrace();
                        System.out.println("转换失败");
                        System.exit(1);
                    }
                    semaphore.release();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    System.exit(1);
                }
                countDownLatch.countDown();
            });
        }
        countDownLatch.await();
        executor.shutdown();
        System.out.println("finish success!");

    }
}

嗯,只记录一下ThreadLocal 的写法,其它写法就不写了。


再说多句,
关于 ThreadLocal 的写法也有几种写法,

// 写法之一
    private static ThreadLocal<SimpleDateFormat> threadLocal3 = new ThreadLocal(){
        @Override
        protected Object initialValue() {
            return new SimpleDateFormat(DATE_FORMAT);
        }
    };

// 写法之二
    private static ThreadLocal<SimpleDateFormat> threadLocal = ThreadLocal.withInitial(() -> new SimpleDateFormat(DATE_FORMAT));

// 写法之三
    private static ThreadLocal<SimpleDateFormat> threadLocal2 = new ThreadLocal();
    private static SimpleDateFormat getDataFormat(){
        SimpleDateFormat simpleDateFormat = threadLocal2.get();
        if(null == simpleDateFormat){
            simpleDateFormat = new SimpleDateFormat(DATE_FORMAT);
            threadLocal2.set(simpleDateFormat);
        }
        return simpleDateFormat;
    }
    // end

嗯。好了。先记一些吧。

标签:static,simpleDateFormat,private,SimpleDateFormat,ThreadLocal,线程,new,多线程
From: https://www.cnblogs.com/aaacarrot/p/17142026.html

相关文章

  • Python的多进程和多线程
    前言:为什么有人说Python的多线程是鸡肋,不是真正意义上的多线程? 看到这里,也许你会疑惑。这很正常,所以让我们带着问题来阅读本文章吧。问题:1.什么是python......
  • 线程
    所有进程共享3~4G的内核空间,所以基于内核之间的通信能够实现。线程之间的通信:  1.不同进程的线程之间要进行通信,那就是进程之间的通信。  2.同一进程的线程间的通......
  • Android中使用线程池
    ArchTaskExecutor是androidx封装的线程接口接口内部是调用Executors开启4个线程的java线程池Executors.newFixedThreadPool(4,newThreadFactory(){切换到子线程......
  • 开源异步并行框架,完成任意的多线程编排、阻塞、等待、串并行结合、强弱依赖
    netty是一个经典的网络框架,提供了基于NIO、AIO的方式来完成少量线程支持海量用户请求连接的模型。netty里面充斥了大量的非阻塞回调模式,主要是靠Future/Promise异步模型来实......
  • springboot 使用@Async注解实现异步多线程
    1、在启动类中添加注解@SpringBootApplication@EnableAsync//@ImportResource(locations={"classpath:spring/my.xml"})publicclassDemoApplication{publi......
  • 自定义线程池
    线程池的基础知识如果不了解线程池,可以先看一下基础知识。详情见:https://www.cnblogs.com/expiator/p/9053754.html线程数的设置详情见:https://www.cnblogs.com/expi......
  • 线程面试top50题
    多线程面试题整理:在典型的Java面试中,面试官会从线程的基本概念问起,如:为什么你需要使用线程,如何创建线程,用什么方式创建线程比较好(比如:继承thread类还是调用Runnable接口......
  • 线程常见面试题
    1.线程和进程有什么区别?进程:程序由指令和数据组成,但这些指令要运行,数据要读写,就必须将指令加载至CPU,数据加载至内存,在指令运行过程中还需要用到磁盘,网络等设备,......
  • 为啥Python多线程爬虫跑的慢?
    单线程和多线程进行数据抓取结果还是大有不同的,但是要值得注意的事,如果多线程没调配好可能连单线程的效率都比不上。本次就和大家一起聊一聊单线程多线程的一些需要注意的......
  • 多线程并发(二):聊聊AQS中的共享锁实现原理
    在上一篇文章多线程并发(一)中我们通过acquire()详细地分析了AQS中的独占锁的获取流程,提到独占锁,自然少不了共享锁,所以我们这边文章就以AQS中的acquireShared()方法为例,......