ThreadLocal 的最佳实践
JAVA2 分钟读完 (大约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 的好处也就立竿见影了。