“Java DateFormat不是线程安全的”这会导致什么? [英] "Java DateFormat is not threadsafe" what does this leads to?

查看:133
本文介绍了“Java DateFormat不是线程安全的”这会导致什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

每个人都警告Java DateFormat不是线程安全的,理论上我理解这个概念。



但是我无法想象我们可能遇到的实际问题这个。比如,我在类中有一个DateFormat字段,并且在多线程环境中的类中的不同方法(格式化日期)中使用相同的字段。



这是否会原因:




  • 格式异常等任何异常

  • 数据差异

  • 任何其他问题?



另外,请解释原因。

解决方案

让我们试一试。



这是一个程序,其中多个线程使用共享 SimpleDateFormat



计划

  public static void main(String [] args)throws Exception {

final DateFormat format = new SimpleDateFormat(yyyyMMdd);

Callable< Date> task = new Callable< Date>(){
public Date call()throws Exception {
return format.parse(20101022);
}
};

//包含5个主题的池
ExecutorService exec = Executors.newFixedThreadPool(5);
列表<未来<日期>> results = new ArrayList< Future< Date>>();

//执行10个日期转换
for(int i = 0; i< 10; i ++){
results.add(exec.submit(task));
}
exec.shutdown();

//查看结果
for(Future< Date> result:results){
System.out.println(result.get());
}
}

运行几次,你会看到:<这是一些例子:



1。

 引起:java.lang.NumberFormatException:对于输入字符串: 
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:48)
at java.lang.Long.parseLong(Long.java:431)
at java.lang.Long.parseLong (Long.java:468)
at java.text.DigitList.getLong(DigitList.java:177)
at java.text.DecimalFormat.parse(DecimalFormat.java:1298)
at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1589)

2。

 引起:java.lang.NumberFormatException:对于输入字符串:。10201E.102014E4
at sun.misc.FloatingDecimal.readJavaFormatString (FloatingDecimal.java:1224)
at java.lang.Double.parseDouble(Double.java:510)
at java.text .DigitList.getDouble(DigitList.java:151)
at java.text.DecimalFormat.parse(DecimalFormat.java:1303)
at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1589)

3。

 引起:java.lang.NumberFormatException:sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1084)的多个点
java.lang.Double.parseDouble的
(Double.java :510)
at java.text.DigitList.getDouble(DigitList.java:151)
at java.text.DecimalFormat.parse(DecimalFormat.java:1303)
at java.text。 SimpleDateFormat.subParse(SimpleDateFormat.java:1936)
at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1312)

结果错误

 周六10月22日00:00:00 BST 2011 
Thu Jan 22 00:00:00 GMT 1970
Fri Oct 22 00:00:00 BST 2010
Fri Oct 22 00:00:00 BST 2010
Fri Oct 22 00:00:00 BST 2010
周四10月22日00:00:00 GMT 1970
星期五10月22日00:00:00 BST 2010
星期五10月22日00:00:00 BST 2010
星期五10月22日00:00:00 BST 2010
Fri Oct 22 00:00:00 BST 2010

正确结果

  Fri Oct 22 00:00:00 BST 2010 
Fri Oct 22 00:00:00 BST 2010
Fri Oct 22 00:00:00 BST 2010
Fri Oct 22 00:00:00 BST 2010
Fri Oct 22 00:00:00 BST 2010
Fri Oct 22 00:00:00 BST 2010
Fri Oct 22 00:00:00 BST 2010
Fri Oct 22 00:00:00 BST 2010
Fri Oct 22 00:00:00 BST 2010
Fri Oct 22 00:00:00 BST 2010






在多线程环境中安全使用DateFormats的另一种方法是使用 ThreadLocal 变量来保存 DateFormat object,这意味着每个线程都有自己的副本,不需要等待其他线程释放它。具体如下:

  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);
返回d;
}
}

这是一个很好的提供更多详情。


Everybody cautions regarding Java DateFormat not being thread safe and I understand the concept theoretically.

But I'm not able to visualize what actual issues we can face due to this. Say, I've a DateFormat field in a class and the same is used in different methods in the class (formatting dates) in a multi-threaded environment.

Will this cause:

  • any exception like format exception
  • discrepancy in data
  • any other issue?

Also, please explain why.

解决方案

Let's try it out.

Here is a program in which multiple threads use a shared SimpleDateFormat.

Program:

public static void main(String[] args) throws Exception {

    final DateFormat format = new SimpleDateFormat("yyyyMMdd");

    Callable<Date> task = new Callable<Date>(){
        public Date call() throws Exception {
            return format.parse("20101022");
        }
    };

    //pool with 5 threads
    ExecutorService exec = Executors.newFixedThreadPool(5);
    List<Future<Date>> results = new ArrayList<Future<Date>>();

    //perform 10 date conversions
    for(int i = 0 ; i < 10 ; i++){
        results.add(exec.submit(task));
    }
    exec.shutdown();

    //look at the results
    for(Future<Date> result : results){
        System.out.println(result.get());
    }
}

Run this a few times and you will see:

Exceptions:

Here are a few examples:

1.

Caused by: java.lang.NumberFormatException: For input string: ""
    at java.lang.NumberFormatException.forInputString(NumberFormatException.java:48)
    at java.lang.Long.parseLong(Long.java:431)
    at java.lang.Long.parseLong(Long.java:468)
    at java.text.DigitList.getLong(DigitList.java:177)
    at java.text.DecimalFormat.parse(DecimalFormat.java:1298)
    at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1589)

2.

Caused by: java.lang.NumberFormatException: For input string: ".10201E.102014E4"
    at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1224)
    at java.lang.Double.parseDouble(Double.java:510)
    at java.text.DigitList.getDouble(DigitList.java:151)
    at java.text.DecimalFormat.parse(DecimalFormat.java:1303)
    at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1589)

3.

Caused by: java.lang.NumberFormatException: multiple points
    at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1084)
    at java.lang.Double.parseDouble(Double.java:510)
    at java.text.DigitList.getDouble(DigitList.java:151)
    at java.text.DecimalFormat.parse(DecimalFormat.java:1303)
    at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1936)
    at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1312)

Incorrect Results:

Sat Oct 22 00:00:00 BST 2011
Thu Jan 22 00:00:00 GMT 1970
Fri Oct 22 00:00:00 BST 2010
Fri Oct 22 00:00:00 BST 2010
Fri Oct 22 00:00:00 BST 2010
Thu Oct 22 00:00:00 GMT 1970
Fri Oct 22 00:00:00 BST 2010
Fri Oct 22 00:00:00 BST 2010
Fri Oct 22 00:00:00 BST 2010
Fri Oct 22 00:00:00 BST 2010

Correct Results:

Fri Oct 22 00:00:00 BST 2010
Fri Oct 22 00:00:00 BST 2010
Fri Oct 22 00:00:00 BST 2010
Fri Oct 22 00:00:00 BST 2010
Fri Oct 22 00:00:00 BST 2010
Fri Oct 22 00:00:00 BST 2010
Fri Oct 22 00:00:00 BST 2010
Fri Oct 22 00:00:00 BST 2010
Fri Oct 22 00:00:00 BST 2010
Fri Oct 22 00:00:00 BST 2010


Another approach to safely use DateFormats in a multi-threaded environment is to use a ThreadLocal variable to hold the DateFormat object, which means that each thread will have its own copy and doesn't need to wait for other threads to release it. This is how:

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;
  }
}

Here is a good post with more details.

这篇关于“Java DateFormat不是线程安全的”这会导致什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆