这篇分享作为一个笔记,原因是今天有人问了我这么一个问题
public class Test {
private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
public static void main(String[] args) throws InterruptedException {
Runnable runnable = new Runnable() {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
try {
sdf.parse("2017-07-28 00:00:00");
} catch (ParseException e) {
e.printStackTrace();
}
}
}
};
for (int i = 0; i < 100; i++) {
Thread thread = new Thread(runnable,"t"+i);
thread.start();
}
}
}
他问我运行这段代码会有什么效果,于是我想起了大概两年前有个面试官问过我这么一个问题,SimpleDateFormart用过么,必然用过啊,对方又问SimpleDateFormat是线程安全的么,我去,这么小的一个工具类,有必要问这个么,这就是我当时的想法,当时我也没看过源码,随便说了个线程不安全,对方又问那如何变得线程安全,我就过脑子都没过的来了句加锁,后来马上补了句加锁效率肯定会低很多,有可能还会造成线程阻塞,对方说那有没有别的可以实现线程安全的方法,我便回答每次用都都创建一个新的对象,不管这题打得怎么样,反正那次面试是没有通过。。
回归正题,这个代码一看就是跑多个线程,每个线程一直调用parse方法进行日期转换,虽然以我现在的水平说不出具体问题所在,不过大概可以知道这应该是一个跟线程安全有关的问题,随即看了下源码,SimpleDateFormat确实不是线程安全的,那么想要避免这个错误,可以加锁但是效率太低没必要,另一种方式就是每次用的时候创建新的format对象
我们看下面代码
public class Test {
public static void main(String[] args) throws InterruptedException {
Runnable runnable = new Runnable() {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
try {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//便于查看结果,打印日期转换
System.out.println(sdf.parse("2017-07-28 00:00:00"));
} catch (ParseException e) {
e.printStackTrace();
}
}
}
};
for (int i = 0; i < 100; i++) {
Thread thread = new Thread(runnable,"t"+i);
thread.start();
}
}
}
比较low,我直接在每次需要用format的时候构造一个新的对象
本次分享其实没有什么实质的意义,也没有什么可学习的知识点,只是想告诫下自己线程安全无处不在,多线程是个好东西,但是也是把双刃剑,使用不慎确实会造成不可预估的风险