当前位置:网站首页>Simpledateformat thread safety issues
Simpledateformat thread safety issues
2022-06-23 07:20:00 【51CTO】
Why are threads unsafe ?
It mainly contains two blocks parse and format unsafe .
You can see , Multiple threads share variables calendar, And modify it calendar. So in a multithreaded environment , When multiple threads use the same SimpleDateFormat object ( Such as static modification ) Words , Such as calling format When the method is used , Multiple threads call at the same time calender.setTime Method , Lead to time Modified by another thread , So threads are not safe .
SimpleDateFormat Of format Method thread insecurity
this.format It uses SimpleDateFormat Of format Method
private StringBuffer format(Date arg0, StringBuffer arg1, FieldDelegate arg2) {
this.calendar.setTime(arg0);
boolean arg3 = this.useDateFormatSymbols();
int arg4 = 0;
while (arg4
<
this.compiledPattern.length)
{
int
arg5 =
this.compiledPattern[arg4]
>>> 8;
int arg6 = this.compiledPattern[arg4++]
& 255;
if (arg6 == 255) {
arg6 = this.compiledPattern[arg4++]
<
< 16;
arg6 |= this.compiledPattern[arg4++];
}
switch (arg5) {
case 100 :
arg1.append((char) arg6);
break;
case 101 :
arg1.append(this.compiledPattern, arg4, arg6);
arg4 += arg6;
break;
default :
this.subFormat(arg5, arg6, arg2, arg1, arg3);
}
}
return arg1;
}
- 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.
Different threads
It will still lead to thread insecurity .
SimpleDateFormat It's inheritance DateFormat class ,DateFormat Maintain one in the class Calendar object
SimpleDateFormat Inherit DateFormat , The use of calendar Parent class DateFormat Medium
public class SimpleDateFormat extends DateFormat {}
DateFormat Of calendar Used for date - Time calculation , It's also used for format Methods are also used for parse Method
public abstract class DateFormat extends Format {
protected Calendar calendar;
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
Parse Resulting in thread safety problems
SimpleDateFormat Of parse Method
public Date parse(String arg0, ParsePosition arg1) {
this.checkNegativeNumberExpression();
int arg2 = arg1.index;
int arg3 = arg2;
int arg4 = arg0.length();
boolean[] arg5 = new boolean[]{false};
CalendarBuilder arg6 = new CalendarBuilder();
int arg7 = 0;
label82 : while (arg7
<
this.compiledPattern.length)
{
int
arg8 =
this.compiledPattern[arg7]
>>> 8;
int arg9 = this.compiledPattern[arg7++]
& 255;
if (arg9 == 255) {
arg9 = this.compiledPattern[arg7++]
<
< 16;
arg9 |= this.compiledPattern[arg7++];
}
switch (arg8) {
case 100 :
if (arg2
<
arg4
&&
arg0.charAt(arg2) =
=
(char)
arg9)
{
++arg2;
break;
}
arg1.index =
arg3;
arg1.errorIndex =
arg2;
return
null;
case
101
:
while
(true)
{
if
(arg9--
<= 0) {
continue label82;
}
if (arg2 >= arg4
|| arg0.charAt(arg2) != this.compiledPattern[arg7++]) {
arg1.index = arg3;
arg1.errorIndex = arg2;
return null;
}
++arg2;
}
default :
boolean arg10 = false;
boolean arg11 = false;
if (arg7
<
this.compiledPattern.length)
{
int
arg12 =
this.compiledPattern[arg7]
>>> 8;
if (arg12 != 100
&
& arg12 != 101) {
arg10 = true;
}
if (this.hasFollowingMinusSign
&
& (arg12 == 100 || arg12 == 101)) {
int arg13;
if (arg12 == 100) {
arg13 = this.compiledPattern[arg7]
& 255;
} else {
arg13 = this.compiledPattern[arg7 + 1];
}
if (arg13 == this.minusSign) {
arg11 = true;
}
}
}
arg2 = this.subParse(arg0, arg2, arg8, arg9, arg10, arg5,
arg1, arg11, arg6);
if (arg2
<
0)
{
arg1.index =
arg3;
return
null;
}
}
}
arg1.index =
arg2;
try
{
Date
arg15 =
arg6.establish(this.calendar).getTime();
if
(arg5[0]
&&
arg15.before(this.defaultCenturyStart))
{
arg15 =
arg6.addYear(100).establish(this.calendar).getTime();
}
return
arg15;
}
catch
(IllegalArgumentException
arg14)
{
arg1.errorIndex =
arg2;
arg1.index =
arg3;
return
null;
}
}
- 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.
- 57.
- 58.
- 59.
- 60.
- 61.
- 62.
- 63.
- 64.
- 65.
- 66.
- 67.
- 68.
- 69.
- 70.
- 71.
- 72.
- 73.
- 74.
- 75.
- 76.
- 77.
- 78.
- 79.
- 80.
- 81.
- 82.
- 83.
- 84.
- 85.
- 86.
- 87.
- 88.
- 89.
- 90.
Key points
Date arg15 = arg6.establish(this.calendar).getTime();
The inside Of establish Method .establish yes CalendarBuilder Methods
Calendar establish(Calendar arg0) {
boolean arg1 = this.isSet(17)
&
& this.field[17] > this.field[1];
if (arg1
&
& !arg0.isWeekDateSupported()) {
if (!this.isSet(1)) {
this.set(1, this.field[35]);
}
arg1 = false;
}
arg0.clear();
int arg2;
int arg3;
for (arg2 = 2; arg2
<
this.nextStamp;
++arg2)
{
for
(arg3 =
0;
arg3
<= this.maxFieldIndex; ++arg3) {
if (this.field[arg3] == arg2) {
arg0.set(arg3, this.field[18 + arg3]);
break;
}
}
}
if (arg1) {
arg2 = this.isSet(3) ? this.field[21] : 1;
arg3 = this.isSet(7) ? this.field[25] : arg0.getFirstDayOfWeek();
if (!isValidDayOfWeek(arg3)
&
& arg0.isLenient()) {
if (arg3 >= 8) {
--arg3;
arg2 += arg3 / 7;
arg3 = arg3 % 7 + 1;
} else {
while (arg3
<
=
0)
{
arg3
+=
7;
--arg2;
}
}
arg3 =
toCalendarDayOfWeek(arg3);
}
arg0.setWeekDate(this.field[35],
arg2,
arg3);
}
return
arg0;
}
- 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.
It mainly depends on
This meeting will calendar Remove , And no new value is set
You know SimpleDateFormat Maintained for format and parse Method to calculate the date - The time of the calendar It's emptied , If the thread at this time A take calendar Empty and no time to set the new value , Threads B Also enter parse The method uses SimpleDateFormat Object calendar object , At this point, thread safety problems will arise !

Solution :
1、 take SimpleDateFormat Defined as a local variable
2、 Add a thread synchronization lock :synchronized(lock)
3、 Use ThreadLocal, Each thread has its own SimpleDateFormat Object copy
Solution chestnut :threadLocal
class ThreadLocalSimpleFormatDateUtil {
private static final String date_format = "yyyy-MM-dd HH:mm:ss";
private static ThreadLocal
<
DateFormat
> threadLocal = new ThreadLocal
<
DateFormat
>();
public static DateFormat getDateFormat() {
DateFormat df = threadLocal.get();
if (df == null) {
df = new SimpleDateFormat(date_format);
threadLocal.set(df);
}
return df;
}
public static String formatDate(Date date) throws ParseException {
return getDateFormat().format(date);
}
public static Date parse(String strDate) throws ParseException {
return getDateFormat().parse(strDate);
}
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
Official account : The community of programmers and developers

Test code
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
class MySimpleDateFormatThread extends Thread {
private SimpleDateFormat sdf;
private String dateString;
public MySimpleDateFormatThread(SimpleDateFormat sdf, String dateString) {
this.sdf = sdf;
this.dateString = dateString;
}
@Override
public void run() {
try {
Date date = sdf.parse(dateString);
String dateStr = sdf.format(date);
if(!dateStr.equals(dateString)) {
System.out.println("ThreadName=" + this.getName() + " Wrong report , Date string :" + dateString + ", Date string converted to :" + dateStr);
} else {
System.out.println("ThreadName=" + this.getName() + " success , Date string :" + dateString);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
public class TestSimpleDateFormat {
public static void main(String[] args) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String[] dateString = {"2017-11-05","2017-11-06","2017-11-07","2017-11-08","2017-11-09","2017-11-10","2017-11-11","2017-11-12","2017-11-13","2017-11-14"};
Thread[] threads = new Thread[10];
for (int i = 0; i
<
threads.length;
i++)
{
threads[i] =
new
MySimpleDateFormatThread(sdf,
dateString[i]);
}
for
(int
i =
0;
i
< threads.length; i++) {
threads[i].start();
}
}
}
- 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.
There will be an error as follows :
ThreadName=Thread-3 Wrong report , Date string :2017-11-08, Date string converted to :2016-12-08
ThreadName=Thread-2 Wrong report , Date string :2017-11-07, Date string converted to :2016-12-08
ThreadName=Thread-7 Wrong report , Date string :2017-11-12, Date string converted to :2016-12-08
ThreadName=Thread-4 Wrong report , Date string :2017-11-09, Date string converted to :2200-11-09
ThreadName=Thread-8 success , Date string :2017-11-13java.lang.NumberFormatException: multiple points
ThreadName=Thread-9 success , Date string :2017-11-14
at sun.misc.FloatingDecimal.readJavaFormatString(Unknown Source)
at sun.misc.FloatingDecimal.parseDouble(Unknown Source)
at java.lang.Double.parseDouble(Unknown Source)
at java.text.DigitList.getDouble(Unknown Source)
at java.text.DecimalFormat.parse(Unknown Source)
at java.text.SimpleDateFormat.subParse(Unknown Source)
at java.text.SimpleDateFormat.parse(Unknown Source)
at java.text.DateFormat.parse(Unknown Source)
at JavaThread.MySimpleDateFormatThread.run(TestSimpleDateFormat.java:34)
java.lang.NumberFormatException: multiple points
at sun.misc.FloatingDecimal.readJavaFormatString(Unknown Source)
at sun.misc.FloatingDecimal.parseDouble(Unknown Source)
at java.lang.Double.parseDouble(Unknown Source)
at java.text.DigitList.getDouble(Unknown Source)
at java.text.DecimalFormat.parse(Unknown Source)
at java.text.SimpleDateFormat.subParse(Unknown Source)
at java.text.SimpleDateFormat.parse(Unknown Source)
at java.text.DateFormat.parse(Unknown Source)
at JavaThread.MySimpleDateFormatThread.run(TestSimpleDateFormat.java:34)
java.lang.NumberFormatException: For input string: ""
at java.lang.NumberFormatException.forInputString(Unknown Source)
at java.lang.Long.parseLong(Unknown Source)
at java.lang.Long.parseLong(Unknown Source)
at java.text.DigitList.getLong(Unknown Source)
at java.text.DecimalFormat.parse(Unknown Source)
at java.text.SimpleDateFormat.subParse(Unknown Source)
at java.text.SimpleDateFormat.parse(Unknown Source)
at java.text.DateFormat.parse(Unknown Source)
at JavaThread.MySimpleDateFormatThread.run(TestSimpleDateFormat.java:34)
java.lang.ArrayIndexOutOfBoundsException: -1
at java.text.DigitList.fitsIntoLong(Unknown Source)
at java.text.DecimalFormat.parse(Unknown Source)
at java.text.SimpleDateFormat.subParse(Unknown Source)
at java.text.SimpleDateFormat.parse(Unknown Source)
at java.text.DateFormat.parse(Unknown Source)
at JavaThread.MySimpleDateFormatThread.run(TestSimpleDateFormat.java:34)
- 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.
边栏推荐
- Advanced drawing skills of Excel lecture 100 (VIII) -excel drawing WiFi diagram
- Deeplab V3 code structure diagram
- Use of Lombok
- In depth learning series 46: face image super score gfp-gan
- The List
- MySQL summary
- Page embedded iframe click browser back problem
- Xshell7 Download
- Flannel 工作原理
- leetcode210. 课程表 II 207. 课程表 拓扑排序 dfs bfs
猜你喜欢

闫氏DP分析法

In depth learning series 47:stylegan summary

Advanced drawing skills of Excel lecture 100 (VIII) -excel drawing WiFi diagram

JUnit unit test reports an error org junit. runners. model. InvalidTestClassError: Invalid test class ‘xxx‘ . No runnable meth

深度学习系列47:styleGAN总结

【博弈论】基础知识

Analyzing the creation principle in maker Education

Akamai-1.75 version-_ Abck parameter generation JS reverse analysis

User mode and kernel mode

U-Net: Convolutional Networks for Biomedical Image Segmentation
随机推荐
Learning and using quartz scheduling framework
How flannel works
闫氏DP分析法
Vs2013 ffmpeg environment configuration and common error handling
Deep learning series 47: Super sub model real esrgan
yolov5检测小目标(附源码)
901. stock price span
junit单元测试报错org.junit.runners.model.InvalidTestClassError: Invalid test class ‘xxx‘ .No runnable meth
Elaborate on the operation of idea
deeplab v3 代码结构图
codeforce 158B Taxi
How to verify date format in PHP (regular)
322. 零钱兑换
307. area and retrieval - array modifiable
codeforce 158B Taxi
Spock约束-调用频率/目标/方法参数
PSP code implementation
SSTable详解
[2022 graduation season] from graduation to transition to the workplace
Spock-sub打桩