先上两个BUG
BUG 1:
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 48 49 50 51 52 53 54 55 56
| package ThreadLocal;
import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date;
public class SimpleDateFormatBugTest {
private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
private static Date parse(String date){ try { return sdf.parse(date); }catch (ParseException e){ e.printStackTrace(); } return null; }
public static void main(String[] args) { Thread thread1 = new Thread(() -> { Date parse = parse("2020-04-24 15:54:59"); System.out.println("第一次执行时间:" + parse); });
Thread thread2 = new Thread(() -> { Date parse = parse("2020-04-25 15:54:59"); System.out.println("第二次执行时间:" + parse); });
Thread thread3 = new Thread(() -> { Date parse = parse("2020-04-26 15:54:59"); System.out.println("第三次执行时间:" + parse); });
thread1.start(); thread2.start(); thread3.start();
try { thread1.join(); thread2.join(); thread3.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("线程退出"); }
}
|
多线程下使用同一个SimpleDateFormat实例将String日期格式转换成Date只能获取到其中一次的结果,其他两个线程出错
BUG 2:
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 48 49 50
| package ThreadLocal;
import java.text.ParseException; import java.util.Date;
public class SimpleDateFormat {
private static java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); private static Date d1 = null; private static Date d2 = null; private static Date d3 = null;
static { try { d1 = sdf.parse("2020-04-24 15:54:59"); d2 = sdf.parse("2020-04-25 15:54:59"); d3 = sdf.parse("2020-04-26 15:54:59"); } catch (ParseException e) { e.printStackTrace(); } } public static void main(String[] args) { Thread thread1 = new Thread(() -> { String format = sdf.format(d1); System.out.println("第一次执行时间:" + format); });
Thread thread2 = new Thread(() -> { String format = sdf.format(d2); System.out.println("第二次执行时间:" + format); });
Thread thread3 = new Thread(() -> { String format = sdf.format(d3); System.out.println("第三次执行时间:" + format); }); thread1.start(); thread2.start(); thread3.start(); System.out.println("线程退出"); } }
|
同样在多线程下如果将Date转成String的话,多个线程共享了同一个数据,导致获取的时间为同一个数据
如何解决
解决方案一:ThreadLocal
原因分析:
SimpleDateFormat是线程不安全的,具体可以从parse(source, pos)
方法中得到答案
1
| parsedDate = calb.establish(calendar).getTime();
|
calendar是成员变量,成员变量在多线程下如果没有锁的限制的话,就很容易出现线程安全问题。
那使用synchronized也可以做到线程安全,但是锁会降低线程的执行效率
解决方案二:synchronized