您的位置:首页 > 职场人生

面试官:ThreadLocal的应用场景和注意事项有哪些?

2020-04-05 10:47 1341 查看
## 前言 ThreadLocal主要有如下2个作用 1. 保证线程安全 2. 在线程级别传递变量 ## 保证线程安全 最近一个小伙伴把项目中封装的日期工具类用在多线程环境下居然出了问题,来看看怎么回事吧 日期转换的一个工具类 ```java public class DateUtil { private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); public static Date parse(String dateStr) { Date date = null; try { date = sdf.parse(dateStr); } catch (ParseException e) { e.printStackTrace(); } return date; } } ``` 然后将这个工具类用在多线程环境下 ```java public static void main(String[] args) { ExecutorService service = Executors.newFixedThreadPool(20); for (int i = 0; i < 20; i++) { service.execute(()->{ System.out.println(DateUtil.parse("2019-06-01 16:34:30")); }); } service.shutdown(); } ``` 结果报异常了,因为部分线程获取的时间不对![在这里插入图片描述](https://img2020.cnblogs.com/other/748509/202004/748509-20200405104725851-804711471.png) 这个异常就不从源码的角度分析了,写一个小Demo,理解了这个小Demo,就理解了原因 一个将数字加10的工具类 ```java public class NumUtil { public static int addNum = 0; public static int add10(int num) { addNum = num; try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } return addNum + 10; } } ``` ```java public static void main(String[] args) { ExecutorService service = Executors.newFixedThreadPool(20); for (int i = 0; i < 20; i++) { int num = i; service.execute(()->{ System.out.println(num + " " + NumUtil.add10(num)); }); } service.shutdown(); } ``` 然后代码的一部分输出为 ```text 0 28 3 28 7 28 11 28 15 28 ``` 什么鬼,不是加10么,怎么都输出了28?这主要是因为线程切换的原因,线程陆续将addNum值设置为0 ,3,7但是都没有执行完(没有执行到return addNum+10这一步)就被切换了,当其中一个线程将addNum值设置为18时,线程陆续开始执行addNum+10这一步,结果都输出了28。SimpleDateFormat的原因和这个类似,那么我们如何解决这个问题呢? ### 解决方案 **解决方案1:每次来都new新的,空间浪费比较大** ```java public class DateUtil { public static Date parse(String dateStr) { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Date date = null; try { date = sdf.parse(dateStr); } catch (ParseException e) { e.printStackTrace(); } return date; } } ``` **解决方案2:方法用synchronized修饰,并发上不来** ```java public class DateUtil { private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); public static synchronized Date parse(String dateStr) { Date date = null; try { date = sdf.parse(dateStr); } catch (ParseException e) { e.printStackTrace(); } return date; } } ``` **解决方案3:用jdk1.8中的日期格式类DateFormatter,DateTimeFormatter** ```java public class DateUtil { private static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); public static LocalDateTime parse(String dateStr) { return LocalDateTime.parse(dateStr, formatter); } } ``` **解决方案4:用ThreadLocal,一个线程一个SimpleDateFormat对象** ```java public class DateUtil { private static ThreadLocal
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: