博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
simpleDateFormat线程不安全
阅读量:5779 次
发布时间:2019-06-18

本文共 5979 字,大约阅读时间需要 19 分钟。

simpleDateFormat是我们比较常用的日期转换类,但是它是一个线程不安全的类。 举例证明

public class DateFormatExample1 {    //请求总数    private static int clientTotal = 1000;    //同时允许执行的线程总数    private static int threadTotal = 20;    private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");    public static void main(String[] args) throws InterruptedException {        final Semaphore semaphore = new Semaphore(threadTotal);        final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);        ExecutorService executorService = Executors.newCachedThreadPool();        for (int i = 0; i < clientTotal; i++) {            executorService.execute(new Runnable() {                @Override                public void run() {                    try {                        semaphore.acquire();                        try {                            simpleDateFormat.parse("2018-09-26");                        } catch (ParseException e) {                            e.printStackTrace();                        }                        semaphore.release();                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                    countDownLatch.countDown();                }            });        }        countDownLatch.await();        executorService.shutdown();    }}

这段代码在运行的过程中,会报错。

Exception in thread "pool-1-thread-2" Exception in thread "pool-1-thread-1" Exception in thread "pool-1-thread-8" Exception in thread "pool-1-thread-9" java.lang.NumberFormatException: For input string: "E.199E1"	at sun.misc.FloatingDecimal.readJavaFormatString(Unknown Source)	at sun.misc.FloatingDecimal.parseDouble(Unknown Source)	at java.lang.Double.parseDouble(Unknown Source)	at java.text.DigitList.getDouble(Unknown Source)	at java.text.DecimalFormat.parse(Unknown Source)	at java.text.SimpleDateFormat.subParse(Unknown Source)	at java.text.SimpleDateFormat.parse(Unknown Source)	at java.text.DateFormat.parse(Unknown Source)	at com.guoy.concurrency.commonUnsafe.DateFormatExample1$1.run(DateFormatExample1.java:31)	at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)	at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)	at java.lang.Thread.run(Unknown Source)java.lang.NumberFormatException: multiple points	at sun.misc.FloatingDecimal.readJavaFormatString(Unknown Source)	at sun.misc.FloatingDecimal.parseDouble(Unknown Source)	at java.lang.Double.parseDouble(Unknown Source)

定义一个静态的SimpleDateFormat实例,是大家在日期工具类中比较通常的写法,但是这种写法在多线程的情况下就会抛出异常。解决方案有很多种:

  • 方法一:在每次使用的时候创建SimpleDateFormat的局部变量,缺点:会创建大量的SimpleDateFormat实例,代码不够简洁优雅。
  • 方法二:其实还有另外一种写法:使用ThradLocal。 ThreadLocal是一个本地线程副本变量工具类。主要用于将私有线程和该线程存放的副本对象做一个映射,各个线程之间的变量互不干扰,在高并发场景下,可以实现无状态的调用,适合于各个线程依赖不同的变量值完成操作的场景。

举例:

package com.guoy.concurrency.commonUnsafe;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;//thread not safepublic class DateFormatExample3 {    //请求总数    private static int clientTotal = 1000;    //同时允许执行的线程总数    private static int threadTotal = 20;    private static ThreadLocal
simpleDateFormat = new ThreadLocal
() { @Override protected SimpleDateFormat initialValue() { return new SimpleDateFormat("yyyy-MM-dd"); } }; public static void main(String[] args) throws InterruptedException { final Semaphore semaphore = new Semaphore(threadTotal); final CountDownLatch countDownLatch = new CountDownLatch(clientTotal); ExecutorService executorService = Executors.newCachedThreadPool(); for (int i = 0; i < clientTotal; i++) { executorService.execute(new Runnable() { @Override public void run() { try { semaphore.acquire(); try { simpleDateFormat.get().parse("2018-09-26"); } catch (ParseException e) { e.printStackTrace(); } semaphore.release(); } catch (InterruptedException e) { e.printStackTrace(); } countDownLatch.countDown(); } }); } countDownLatch.await(); executorService.shutdown(); }}
  • 方法三:使用joda-time(推荐使用)

引入maven依赖

joda-time
joda-time
2.9.9
import org.joda.time.DateTime;import org.joda.time.format.DateTimeFormat;import org.joda.time.format.DateTimeFormatter;public class DateFormatExample2 {    //请求总数    private static int clientTotal = 1000;    //同时允许执行的线程总数    private static int threadTotal = 20;    private static DateTimeFormatter dateTimeFormatter = DateTimeFormat.forPattern("yyyy-MM-dd");    public static void main(String[] args) throws InterruptedException {        final Semaphore semaphore = new Semaphore(threadTotal);        final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);        ExecutorService executorService = Executors.newCachedThreadPool();        for (int i = 0; i < clientTotal; i++) {            executorService.execute(new Runnable() {                @Override                public void run() {                    try {                        semaphore.acquire();                        DateTime.parse("2018-12-04", dateTimeFormatter).toDate();                        semaphore.release();                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                    countDownLatch.countDown();                }            });        }        countDownLatch.await();        executorService.shutdown();    }

转载于:https://my.oschina.net/wuyiyi/blog/2967466

你可能感兴趣的文章
WPF程序加入3D模型
查看>>
头文件中尽量少引用命名空间
查看>>
Build a Basic CRUD App with Vue.js and nodejs
查看>>
Oracle学习笔记整理手册
查看>>
WPF模板(二)应用
查看>>
Java 8 Streams filter examples
查看>>
Java数组的基本讲解
查看>>
MS CRM 2011 剖析Ribbon与背后的Jscript
查看>>
云:构建云计算的核心技术与平台
查看>>
DOCUMENT.GETELEMENTBYID使用
查看>>
一生中很值得看的30个故事之一断箭
查看>>
Android五大基本组件之一-----Service篇
查看>>
DHCP与BOOTP有什么区别
查看>>
电子书下载:Pro ASP.NET MVC 3 Framework 3rd Edition
查看>>
哎,累死了 加班加到八点半才解决问题
查看>>
MATLAB Builder for .NET
查看>>
C#生成唯一码方法
查看>>
Windows mobile 开发入门—环境搭建(转)
查看>>
Caused by: java.lang.OutOfMemoryError: Java heap space解决方案
查看>>
DM365视频处理流程/DM368 NAND Flash启动揭秘
查看>>