2017-02-14 2021-04-07 JAVA 2 分钟读完 (大约342个字) SimpleDateFormat
众所周知是线程不安全的,多线程中如何保证线程安全又同时兼顾性能问题呢?那就是使用 ThreadLocal
维护 SimpleDateFormat
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 public class SimpleDateFormatThreadTest { static volatile AtomicInteger n = new AtomicInteger(-1 ); <!-- more --> static ThreadLocal<DateFormat> sdf ; static { sdf =new ThreadLocal<DateFormat>() { @Override protected DateFormat initialValue () { return new SimpleDateFormat("yyyy-MM-dd" ); } }; } public static void main (String[] args) throws ParseException, InterruptedException { Set<String> dateSet = new ConcurrentHashSet<>(); Set<Integer> numberSet = new ConcurrentHashSet<>(); Date[] dates = new Date[1000 ]; for (int i = 0 ; i < 1000 ; i++) { dates[i] = sdf.get().parse(i + 1000 + "-11-22" ); } ExecutorService executorService = Executors.newFixedThreadPool(10 ); for (int i=0 ;i<1000 ;i++){ executorService.execute(new Runnable() { @Override public void run () { int number = n.incrementAndGet(); String date = sdf.get().format(dates[number]); numberSet.add(number); dateSet.add(date); System.out.println(number+" " +date); } }); } executorService.shutdown(); Thread.sleep(5000 ); System.out.println(dateSet.size()); System.out.println(numberSet.size()); } }
实践证明 sdf 的 parse(String to Date)有严重的线程安全问题,format(Date to String)有轻微的线程安全问题,虽然不太明显,但还是会出现问题,这和内部的实现有关。
简单分析下使用 ThreadLocal 的好处,1000 次转换操作,10 个线程争抢执行,如果每次都去 new 一个 sdf,可见其效率之低,而使用 ThreadLocal,是对每个线程维护一个 sdf,所以最多就只会出现 10 个 sdf,真正项目中,由于操作系统线程分片执行,所以线程不会非常的多,使用 ThreadLocal 的好处也就立竿见影了。