I have a class as
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.experimental.FieldDefaults;
import lombok.extern.slf4j.Slf4j;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.ZoneId;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/***
* Builds the required employee jod data records by fetching the same from
* the available sources(PDL for now) and validating the response.
*/
@Slf4j
@AllArgsConstructor
@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true)
public class EmployeeJobDataBuilder {
EmployeeJobDataAccessor employeeJobDataAccessor;
private final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
private List<EmployeeJobData> filterEmployeeJobDataEntriesForStringDates(final List<EmployeeJobData> preFilterEntries,
final String rangeStartDateString,
final String rangeEndDateString,
final EmployeeJobData filterJobData){
if(CollectionUtils.isNullOrEmpty(preFilterEntries)){
log.info("filterJobDataEntriesForStringDates: preFilterEntries.size- 0");
return Collections.emptyList();
}
log.info("filterJobDataEntriesForStringDates: preFilterEntries.size- {}", preFilterEntries.size());
List<EmployeeJobData> filteredEntries = preFilterEntries.stream()
.filter(entry -> this.parseAndCompare(entry.getEffEndDateString(), rangeStartDateString))
.filter(entry -> this.parseAndCompare(rangeEndDateString, entry.getEffStartDateString()))
.collect(Collectors.toList());
log.info("filterJobDataEntriesForStringDates: filteredEntries.size: {}", filteredEntries.size());
return filteredEntries;
}
private boolean parseAndCompare(final String date1, final String date2){
try {
return this.dateFormat.parse(date1).compareTo(this.dateFormat.parse(date2)) >= 0;
} catch (final ParseException parseException) {
log.warn("Exception occurred while parsing string date");
}
return false;
}
}
Here I am using SimpleDateFormat as defined above and parsing using it, however I get inconsistent results, the call which fails for some parameters gets succeeded the next time within milliseconds with same parameters (What I mean is that the parsing gives incorrect results which I why it happens)
I referred some articles Why is Java's SimpleDateFormat not thread-safe? saying that this Java Library is not thread safe and that is why it happens
Also the class in which this date format is being used is a Singleton class with definition as:-
@Provides
@Singleton
public EmployeeJobDataBuilder getEmployeeJobDataBuilder(final EmployeeJobDataAccessor employeeJobDataAccessor){
return new EmployeeJobDataBuilder(employeeJobDataAccessor);
}
Is it related to Thread safety issue?
Because I tried to mock it with a test class having this behaviour
import edu.emory.mathcs.backport.java.util.concurrent.ConcurrentHashMap;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.ZoneId;
import java.util.Date;
import java.util.Map;
class MultithreadingDemo extends Thread {
final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
Map<Date, Integer> map = new ConcurrentHashMap();
public void run()
{
try {
final String payEndDateString = LocalDate.parse("2021-12-18").atTime(LocalTime.MAX)
.atZone(ZoneId.of("America/New_York")).toString();
Date d = dateFormat.parse(payEndDateString);
map.put(d,1);
if(map.size()>=2) {
System.out.println("Yes" + map);
}
} catch (ParseException parseException) {
System.out.println(parseException);
}
catch (Exception e) {
// Throwing an exception
System.out.println("Exception is caught");
}
}
}
// Main Class
public class Multithread {
public static void main(String[] args) {
int n = 800000; // Number of threads
for (int i = 0; i < n; i++) {
MultithreadingDemo object
= new MultithreadingDemo();
object.start();
}
}
}
Here in my opinion I should have got 2 values in map if parsing gives incorrect results at any point in time but I was unable to see this.
Can someone please help?