Home  >  Q&A  >  body text

Java SImpleDateFormat线程安全问题

public class Test {
    private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

    private static class Task implements Runnable {

        public void run() {
            try {
                System.out.println(sdf.parse("2016-03-21 12:00:00").getTime());
            } catch (ParseException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        Task task = new Task();

        Thread t1 = new Thread(task);
        t1.start();
        Thread t2 = new Thread(task);
        t2.start();
        Thread t3 = new Thread(task);
        t3.start();
        Thread t4 = new Thread(task);
        t4.start();
        Thread t5 = new Thread(task);
        t5.start();
    }
}

最近才知道,如果像上面代码那样通过定义静态共享的实例来使用SimpleDateFormat是会存在线程安全问题的。

例如线程被挂死:

或者转换的时间不对:

然后自己尝试读JDK源码来试图分析在SimpleDateFormat的代码中,究竟是哪里的函数或者代码会引起线程不安全,但是由于水平有限,最后还是找不出。

哪位大牛可以帮忙分析一下。

PS:我的jdk版本:1.8.0_73

PHP中文网PHP中文网2764 days ago493

reply all(3)I'll reply

  • ringa_lee

    ringa_lee2017-04-17 17:33:32

    I took a look at the comments of the parse() source code, and there is a section by this guy

    This parsing operation uses the {@link DateFormat#calendar

    • calendar} to produce a {@code Date}. All of the {@code

    • calendar}'s date-time fields are {@linkplain Calendar#clear()

    • cleared} before parsing, and the {@code calendar}'s default

    • values ​​of the date-time fields are used for any missing

    • date-time information.

    It probably means that the parse() method uses calendar to generate the returned Date instance. The problem is that the calendar it uses here is not a new one every time the method is executed. It defines a "protected Calendar calendar" attribute , according to the meaning of the comment, before each parse, all relevant attributes in the calendar will be cleared, and then the object will be filled with new processing results. In this case, in multi-threading, a thread will appear during the execution of parse() After setting the calendar, another thread cleared it. Because it is an sdf instance, other problems should be caused by this

    reply
    0
  • PHP中文网

    PHP中文网2017-04-17 17:33:32

    private StringBuffer format(Date date, StringBuffer toAppendTo,
                                    FieldDelegate delegate) {
            // Convert input date to time field list
            calendar.setTime(date);
    
            boolean useDateFormatSymbols = useDateFormatSymbols();
            
            ...
     }  
    
    

    The calendar used here is a class member, and multi-threading setTime will cause thread safety issues

    reply
    0
  • 伊谢尔伦

    伊谢尔伦2017-04-17 17:33:32

    This has nothing to do with the implementation of SimpleDateFormat. It has to do with your multi-threaded use of the same object and failure to synchronize threads

    reply
    0
  • Cancelreply