天天看点

有关Java的日期处理的一些杂记

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

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

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

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

确保不会在多线程状态下使用同一个 dateformat 或者 simpledateformat 实例

如果多线程情况下需要访问同一个实例,那么请用同步方法

你也可以使用 commons-lang 包中的 fastdateformat 工具类

另外你也可以使用 threadlocal 来处理这个问题

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

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

1

2

3

4

5

6

7

8

9

10

11

<code>public</code> <code>class</code> <code>dateformattest {</code>

<code> </code> 

<code>  </code><code>private</code> <code>final</code> <code>dateformat format =</code>

<code>            </code><code>new</code> <code>simpledateformat(</code><code>"yyyymmdd"</code><code>);</code>

<code>  </code><code>public</code> <code>date convert(string source)</code>

<code>                      </code><code>throws</code> <code>parseexception{</code>

<code>    </code><code>date d = format.parse(source);</code>

<code>    </code><code>return</code> <code>d;</code>

<code>  </code><code>}</code>

<code>}</code>

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

12

13

14

15

16

17

18

19

20

21

22

<code>final</code> <code>dateformattest t =</code><code>new</code> <code>dateformattest();</code>

<code>callable&lt;date&gt; task =</code><code>new</code> <code>callable&lt;date&gt;(){</code>

<code>    </code><code>public</code> <code>date call()</code><code>throws</code> <code>exception {</code>

<code>        </code><code>return</code> <code>t.convert(</code><code>"20100811"</code><code>);</code>

<code>    </code><code>}</code>

<code>};</code>

<code>//让我们尝试2个线程的情况</code>

<code>executorservice exec = executors.newfixedthreadpool(</code><code>2</code><code>);</code>

<code>list&lt;future&lt;date&gt;&gt; results =</code>

<code>             </code><code>new</code> <code>arraylist&lt;future&lt;date&gt;&gt;();</code>

<code>//实现5次日期转换</code>

<code>for</code><code>(</code><code>int</code> <code>i =</code><code>0</code><code>; i &lt;</code><code>5</code><code>; i++){</code>

<code>    </code><code>results.add(exec.submit(task));</code>

<code>exec.shutdown();</code>

<code>//查看结果</code>

<code>for</code><code>(future&lt;date&gt; result : results){</code>

<code>    </code><code>system.out.println(result.get());</code>

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

如何并发使用dateformat类

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

1. 同步

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

<code>public</code> <code>date convert(string source)</code>

<code>                    </code><code>throws</code> <code>parseexception{</code>

<code>  </code><code>synchronized</code><code>(format) {</code>

  

2. 使用threadlocal

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

<code>  </code><code>private</code> <code>static</code> <code>final</code> <code>threadlocal&lt;dateformat&gt; df</code>

<code>                 </code><code>= </code><code>new</code> <code>threadlocal&lt;dateformat&gt;(){</code>

<code>    </code><code>@override</code>

<code>    </code><code>protected</code> <code>dateformat initialvalue() {</code>

<code>        </code><code>return</code> <code>new</code> <code>simpledateformat(</code><code>"yyyymmdd"</code><code>);</code>

<code>  </code><code>};</code>

<code>                     </code><code>throws</code> <code>parseexception{</code>

<code>    </code><code>date d = df.get().parse(source);</code>

  3. joda-time

<code>import</code> <code>org.joda.time.datetime;</code>

<code>import</code> <code>org.joda.time.format.datetimeformat;</code>

<code>import</code> <code>org.joda.time.format.datetimeformatter;</code>

<code>import</code> <code>java.util.date;</code>

<code>  </code><code>private</code> <code>final</code> <code>datetimeformatter fmt =</code>

<code>       </code><code>datetimeformat.forpattern(</code><code>"yyyymmdd"</code><code>);</code>

<code>  </code><code>public</code> <code>date convert(string source){</code>

<code>    </code><code>datetime d = fmt.parsedatetime(source);</code>

<code>    </code><code>returnd.todate();</code>