這篇分享作爲一個筆記,原因是今天有人問了我這麼一個問題
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的時候構造一個新的對象
本次分享其實沒有什麼實質的意義,也沒有什麼可學習的知識點,只是想告誡下自己線程安全無處不在,多線程是個好東西,但是也是把雙刃劍,使用不慎確實會造成不可預估的風險