Java在并发环境中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,整个转换过程都不需要考虑线程安全的问题。

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

(0)

相关推荐

  • 详解Java中格式化日期的DateFormat与SimpleDateFormat类

    DateFormat 1. DateFormat 介绍 DateFormat 的作用是 格式化并解析"日期/时间".实际上,它是Date的格式化工具,它能帮助我们格式化Date,进而将Date转换成我们想要的String字符串供我们使用 不过DateFormat的格式化Date的功能有限,没有SimpleDateFormat强大:但DateFormat是SimpleDateFormat的父类.所以,我们先对DateFormat有个整体了解,然后再学习SimpleDateFormat.

  • JAVA使用SimpleDateFormat类表示时间代码实例

    在程序开发中,经常需要处理日期和时间的相关数据,此时我们可以使用 java.util 包中的 Date 类.这个类最主要的作用就是获取当前时间,我们来看下 Date 类的使用: 使用 Date 类的默认无参构造方法创建出的对象就代表当前时间,我们可以直接输出 Date 对象显示当前的时间,显示的结果如下: 其中, Wed 代表 Wednesday (星期三), Jun 代表 June (六月), 11 代表 11 号, CST 代表 China Standard Time (中国标准时间,也就是

  • Java SimpleDateFormat中英文时间格式化转换详解

    SimpleDateFormat是一个以与语言环境有关的方式来格式化和解析日期的具体类.它允许进行格式化(日期 -> 文本).解析(文本 -> 日期)和规范化. SimpleDateFormat使得可以选择任何用户定义的日期-时间格式的模式.但是,仍然建议通过DateFormat中的getTimeInstance.getDateInstance 或 getDateTimeInstance 来创建日期-时间格式器.每一个这样的类方法都能够返回一个以默认格式模式初始化的日期/时间格式器.可以根据需

  • java日期格式化SimpleDateFormat的使用详解

    日期和时间格式由 日期和时间模式字符串 指定.在 日期和时间模式字符串 中,未加引号的字母 'A' 到 'Z' 和 'a' 到 'z' 被解释为模式字母,用来表示日期或时间字符串元素.文本可以使用单引号 (') 引起来,以免进行解释.所有其他字符均不解释:只是在格式化时将它们简单复制到输出字符串 白话文的讲:这些A--Z,a--z这些字母(不被单引号包围的)会被特殊处理替换为对应的日期时间,其他的字符串还是原样输出. 日期和时间模式(注意大小写,代表的含义是不同的) yyyy:年 MM:月 dd

  • 详解SimpleDateFormat的线程安全问题与解决方案

    1. 原因 SimpleDateFormat(下面简称sdf)类内部有一个Calendar对象引用,它用来储存和这个sdf相关的日期信息,例如sdf.parse(dateStr), sdf.format(date) 诸如此类的方法参数传入的日期相关String, Date等等, 都是交友Calendar引用来储存的.这样就会导致一个问题,如果你的sdf是个static的, 那么多个thread 之间就会共享这个sdf, 同时也是共享这个Calendar引用, 并且, 观察 sdf.parse()

  • Java中SimpleDateFormat用法详解

    public class SimpleDateFormat extends DateFormat SimpleDateFormat 是一个以国别敏感的方式格式化和分析数据的具体类. 它允许格式化 (date -> text).语法分析 (text -> date)和标准化. SimpleDateFormat 允许以为日期-时间格式化选择任何用户指定的方式启动. 但是,希望用 DateFormat 中的 getTimeInstance. getDateInstance 或 getDateTime

  • Java中SimpleDateFormat日期格式转换详解及代码示例

    SimpleDateFormat是处理日期格式转换的类. 官方API_1.8关于SimpleDateFormat继承于DateFormate截图: SimpleDateFormat的构造器如下: SimpleDateFormat中的格式定义,常用的用红色框圈出: 中文解释: y : 年 M : 年中的月份 D : 年中的天数 d : 月中的天数 w : 年中的周数 W : 月中的周数 a : 上下/下午 H : 一天中的小时数(0-23) h : 一天中的小时数(0-12) m : 小时中的分钟

  • Java中SimpleDateFormat的使用方法

    本文内容大多基于官方文档和网上前辈经验总结,经过个人实践加以整理积累,仅供参考. java.text.SimpleDateFormat 以区域语言环境敏感的方式格式化和解析日期,可以将日期格式化为指定字符串和将字符串解析成日期. java.text.SimpleDateFormat 可以根据用户定义的模式格式化日期 @Test public void test() { Calendar calendar = Calendar.getInstance(); calendar.set(2016, 1

  • Java在并发环境中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 SimpleDateForm

  • java关于并发模型中的两种锁知识点详解

    1.悲观锁 悲观锁假设最坏的情况(如果果你不锁门,那么捣蛋鬼就会闯入并搞得一团糟),只有在确保其他线程不受干扰(获得正确的锁)的情况下才能执行. 一般实现如独占锁等. 安全性更高,但中低并发性效率更低. 2.乐观锁 乐观锁通过冲突检查机制判断更新过程中是否存在其他线程干扰.如果存在,操作将失败,重试(也可以不重试). CAS等常见实现. 一些乐观锁削弱了一致性,但在中低并发性下效率大大提高. 知识点扩展: 并行与分布式编程 关注的是复杂软件系统的构造,"复杂"是指多线程.分布式与GUI

  • Java+Spring+MySql环境中安装和配置MyBatis的教程

    1.MyBatis简介与配置MyBatis+Spring+MySql 1.1MyBatis简介       MyBatis 是一个可以自定义SQL.存储过程和高级映射的持久层框架.MyBatis 摒除了大部分的JDBC代码.手工设置参数和结果集重获.MyBatis 只使用简单的XML 和注解来配置和映射基本数据类型.Map 接口和POJO 到数据库记录.相对Hibernate和Apache OJB等"一站式"ORM解决方案而言,Mybatis 是一种"半自动化"的O

  • 详解java解决分布式环境中高并发环境下数据插入重复问题

    java 解决分布式环境中 高并发环境下数据插入重复问题 前言 原因:服务器同时接受到的重复请求 现象:数据重复插入 / 修改操作 解决方案 : 分布式锁 对请求报文生成 摘要信息 + redis 实现分布式锁 工具类 分布式锁的应用 package com.nursling.web.filter.context; import com.nursling.nosql.redis.RedisUtil; import com.nursling.sign.SignType; import com.nu

  • 深入解析Java并发程序中线程的同步与线程锁的使用

    synchronized关键字 synchronized,我们谓之锁,主要用来给方法.代码块加锁.当某个方法或者代码块使用synchronized时,那么在同一时刻至多仅有有一个线程在执行该段代码.当有多个线程访问同一对象的加锁方法/代码块时,同一时间只有一个线程在执行,其余线程必须要等待当前线程执行完之后才能执行该代码段.但是,其余线程是可以访问该对象中的非加锁代码块的. synchronized主要包括两种方法:synchronized 方法.synchronized 块. synchron

  • 并发环境下mysql插入检查方案

    业务背景: 基本业务场景是这样的,请求数据(车辆vin信息)进入到接口中,需要先判断其在数据库中的状态,如果库中不存在该vin,或者该vin状态位为"1(已完成)",则执行一些检查操作后,将数据插入到数据库中,此时新增vin状态为0,调用人工处理接口,十分钟后返回结果,将状态置为1.如果其状态位为"0(正在处理)"则驳回操作,返回提示信息. 在单线程环境下,这样的业务没有问题,然而当并发访问接口时,会出现同时进入两条vin相同的请求AB,正常情况应该插入一条A,驳回

  • java高并发情况下高效的随机数生成器

    前言 在代码中生成随机数,是一个非常常用的功能,并且JDK已经提供了一个现成的Random类来实现它,并且Random类是线程安全的. 下面是Random.next()生成一个随机整数的实现: protected int next(int bits) { long oldseed, nextseed; AtomicLong seed = this.seed; do { oldseed = seed.get(); nextseed = (oldseed * multiplier + addend)

  • Java多线程并发开发之DelayQueue使用示例

    在学习Java 多线程并发开发过程中,了解到DelayQueue类的主要作用:是一个无界的BlockingQueue,用于放置实现了Delayed接口的对象,其中的对象只能在其到期时才能从队列中取走.这种队列是有序的,即队头对象的延迟到期时间最长.注意:不能将null元素放置到这种队列中. Delayed,一种混合风格的接口,用来标记那些应该在给定延迟时间之后执行的对象.此接口的实现必须定义一个 compareTo 方法,该方法提供与此接口的 getDelay 方法一致的排序. 在网上看到了一些

  • 浅谈Java高并发解决方案以及高负载优化方法

    目录 1.HTML静态化 2.图片服务器分离 3.数据库集群和库表散列 4.缓存 5.镜像 6.负载均衡 1)硬件四层交换 2)软件四层交换 一.高并发高负载类网站关注点之数据库 需要注意的是: 二.高并发高负载网站的系统架构之HTML静态化 网站HTML静态化解决方案 : 三.高并发高负载类网站关注点之缓存.负载均衡.存储 负载均衡/加速 存储 四.高并发高负载网站的系统架构之图片服务器分离 利用Apache实现图片服务器的分离,缘由: 环境介绍: 步骤: 五.高并发高负载网站的系统架构之数据

  • 集群环境中使用ehcache_动力节点Java学院整理

    EhCache 是一个纯 Java 的进程内缓存框架,具有快速.精干等特点,是 Hibernate 中默认的 CacheProvider. 下图是 EhCache 在应用程序中的位置: EhCache 的主要特性有: 1.快速: 2.简单: 3.多种缓存策略: 4.缓存数据有两级:内存和磁盘,因此无需担心容量问题: 5.缓存数据会在虚拟机重启的过程中写入磁盘: 6.可以通过 RMI.可插入 API 等方式进行分布式缓存: 7.具有缓存和缓存管理器的侦听接口: 8.支持多缓存管理器实例,以及一个实

随机推荐