在企业应用开发中,经常会遇到日期的相关处理,说实话JDK自带的日期方法很难用。就我个人而言我一般都会采用joda-time来替代JDK自身的日期。

这篇文章是杂记,所以写的比较零散,希望大家不要见怪。

SimpleDateFormat

先来说说JDK自带的SimpleDateFormat类吧。SimpleDateFormat 是 Java 中一个非常常用的类用来对日期字符串进行解析和格式化输出,但如果使用不小心会导致非常微妙和难以调试的问题,因为 DateFormat 和 SimpleDateFormat 类不都是线程安全的,在多线程环境下调用 format() 和 parse() 方法应该使用同步代码来避免问题。

下面是你在使用 SimpleDateFormat 应该要小心的几点:

  • 确保不会在多线程状态下使用同一个 DateFormat 或者 SimpleDateFormat 实例
  • 如果多线程情况下需要访问同一个实例,那么请用同步方法
  • 可以使用JODA日期时间处理库来避免这些问题
  • 你也可以使用 commons-lang 包中的 FastDateFormat 工具类
  • 另外你也可以使用 ThreadLocal 来处理这个问题

下面我们通过代码来说明上面的问题:

以下的代码为我们展示了如何在一个线程环境里面使用DateFormat把字符串日期转换为日期对象。创建一个实例来获取日期格式会比较高效,因为系统不需要多次获取本地语言和国家。

public class DateFormatTest {

  private final DateFormat format =
new SimpleDateFormat("yyyyMMdd"); public Date convert(String source)
throws ParseException{
Date d = format.parse(source);
return d;
}
}

  这段代码是非线程安全的。我们可以通过在多个线程中调用它。在以下调用的代码中,我创建了一个有两个线程的线程池,并提交了5个日期转换任务,之后查看运行结果:

final DateFormatTest t =new DateFormatTest();
Callable<Date> task =new Callable<Date>(){
public Date call()throws Exception {
return t.convert("20100811");
}
}; //让我们尝试2个线程的情况
ExecutorService exec = Executors.newFixedThreadPool(2);
List<Future<Date>> results =
new ArrayList<Future<Date>>(); //实现5次日期转换
for(int i =0; i <5; i++){
results.add(exec.submit(task));
}
exec.shutdown(); //查看结果
for(Future<Date> result : results){
System.out.println(result.get());
}

  代码的运行结果并非如我们所愿 - 有时候,它输出正确的日期,有时候会输出错误的(例如.Sat Jul 31 00:00:00 BST 2012),有些时候甚至会抛出NumberFormatException!

如何并发使用DateFormat类

我们可以有多种方法在线程安全的情况下使用DateFormat类。

1. 同步

最简单的方法就是在做日期转换之前,为DateFormat对象加锁。这种方法使得一次只能让一个线程访问DateFormat对象,而其他线程只能等待。

public Date convert(String source)
throws ParseException{
synchronized(format) {
Date d = format.parse(source);
return d;
}
}

  

2. 使用ThreadLocal

另外一个方法就是使用ThreadLocal变量去容纳DateFormat对象,也就是说每个线程都有一个属于自己的副本,并无需等待其他线程去释放它。这种方法会比使用同步块更高效。

public class DateFormatTest {

  private static final ThreadLocal<DateFormat> df
= new ThreadLocal<DateFormat>(){
@Override
protected DateFormat initialValue() {
return new SimpleDateFormat("yyyyMMdd");
}
}; public Date convert(String source)
throws ParseException{
Date d = df.get().parse(source);
return d;
}
}

  3. Joda-Time

Joda-Time 是一个很棒的开源的 JDK 的日期和日历 API 的替代品,其 DateTimeFormat 是线程安全而且不变的。

import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import java.util.Date; public class DateFormatTest { private final DateTimeFormatter fmt =
DateTimeFormat.forPattern("yyyyMMdd"); public Date convert(String source){
DateTime d = fmt.parseDateTime(source);
returnd.toDate();
}
}

  

有关Java的日期处理的一些杂记的更多相关文章

  1. [转载]Java 8 日期&时间 API

    Java 8 日期和时间 声明 本文转自http://www.journaldev.com/2800/java-8-date-localdate-localdatetime-instant,以mark ...

  2. 【转】JAVA 8 日期/时间(Date Time)API指南

    前言 本来想写下Java 8的日期/时间API,发现已经有篇不错的文章了,那就直接转载吧~ PS:主要内容没变,做了部分修改. 原文链接: journaldev 翻译: ImportNew.com - ...

  3. 记一个JAVA关于日期的坑

    JAVA解析日期格式代码,之前一直写成:“yyyy-MM-dd hh:mm”,比如"2016-01-18 11:00"."2016-01-18 15:00"都可 ...

  4. java获取日期之间的差异

    转载请注明出处.谢谢http://blog.csdn.net/harryweasley/article/details/42121485 当想到要计算差值.我们肯定想的是"2014.12.1 ...

  5. java 获取日期的几天前,几个月前和几年前

    java 获取日期的几天前,几个月前和几年前. package bys.utils; import java.util.Date; /** * Created by toutou on 2015/3/ ...

  6. Java 8 日期时间 API

    转自:https://www.runoob.com/java/java8-datetime-api.html Java 8通过发布新的Date-Time API (JSR 310)来进一步加强对日期与 ...

  7. JAVA 8 日期工具类

    JAVA 8 日期工具类 主题描述 JAVA中日期时间的历史 代码成果 主题描述 JAVA的日期时间一直比较混乱,本来以为joda会是巅峰,但是JAVA 8改变了我的思想.但是即便在JAVA 8面前, ...

  8. Java 8 新特性-菜鸟教程 (8) -Java 8 日期时间 API

    Java 8 日期时间 API Java 8通过发布新的Date-Time API (JSR 310)来进一步加强对日期与时间的处理. 在旧版的 Java 中,日期时间 API 存在诸多问题,其中有: ...

  9. Java Date 日期 时间 相关方法

    DateTools.java import java.text.SimpleDateFormat; import java.util.Date; /** * 日期操作类 */ public class ...

随机推荐

  1. easyui layout 折叠后显示标题

    (function($){ var buttonDir = {north:'down',south:'up',east:'left',west:'right'}; $.extend($.fn.layo ...

  2. Android -- Adapter

    体系 public interface Adapter----0层(表示继承体系中的层次)  public interface ExpandableListAdapter---(无所谓层次因为没有其他 ...

  3. 小记sql server临时表与表变量的区别

    临时表与表变量都可以起到“临时”的作用,那么两者主要的区别是什么呢? 这里不讨论创建方式,以及全局临时表.会话临时表这些,主要记录一下个人对两者的主要区别以及适用情况的看法,有什么不对或补充的地方,欢 ...

  4. 关于Task的线程窃取

    示例代码: static void Main(string[] args) { ThreadPool.SetMaxThreads(, ); object locker = new object(); ...

  5. lambda函数、lambda表达式

    C++11 新特性:Lambda 表达式 豆子 2012年5月15日 C++ 10条评论 参考文章:https://blogs.oracle.com/pcarlini/entry/c_1x_tidbi ...

  6. javascript面试题(一)

    答案和解析在问题下一行,为白色字体 单选题 1.以下哪条语句会产生运行错误:(a) A.var obj = ();//语法错误 B.var obj = [];//创建数组 C.var obj = {} ...

  7. jquery+bootstrap使用数字增减按钮

    <div class="container"> <div class="page-header"><h1>Bootstrap ...

  8. 【jQuery EasyUI系列】使用属性介绍

    1.ValidateBox The validatebox is designed to validate the form input fields.If users enter invalid v ...

  9. jQuery基础--样式篇(4)

    jQuery选择器: 1.id选择器:通过id名来获取节点,id是唯一的,每个id在页面上只能使用一次. $( "#id" ) 2.类选择器:通过class样式类名来获取节点 $( ...

  10. 【POJ 1743】Musical Theme

    后缀数组求了height,模板题啦啦啦 #include<cstdio> #include<cstring> #include<algorithm> using n ...