9

I have a requirement to convert incoming date string format "20130212" (YYYYMMDD) to 12/02/2013 (DD/MM/YYYY)

using ThreadLocal. I know a way to do this without the ThreadLocal. Can anyone help me?

Conversion without ThreadLocal:

    final SimpleDateFormat format2 = new SimpleDateFormat("MM/dd/yyyy");
    final SimpleDateFormat format1 = new SimpleDateFormat("yyyyMMdd");
    final Date date = format1.parse(tradeDate);
    final Date formattedDate = format2.parse(format2.format(date));
dimo414
  • 47,227
  • 18
  • 148
  • 244
user2680017
  • 101
  • 1
  • 2
  • 9
  • 1
    Why do you need to use a ThreadLocal? – JohnMark13 Sep 03 '13 at 10:39
  • Because SimpleDateFormats (and indeed most other Format instances) are not thread-safe. See my [blog post](https://stijndewitt.wordpress.com/2014/07/28/how-javas-text-formats-can-subtly-break-your-code/) on this topic. – Stijn de Witt Jul 28 '14 at 21:06

3 Answers3

14

The idea behind this is that SimpleDateFormat is not thread-safe so in a mutil-threaded app you cannot share an instance of SimpleDateFormat between multiple threads. But since creation of SimpleDateFormat is an expensive operation we can use a ThreadLocal as workaround

static ThreadLocal<SimpleDateFormat> format1 = new ThreadLocal<SimpleDateFormat>() {
    @Override
    protected SimpleDateFormat initialValue() {
        return new SimpleDateFormat("yyyy-MM-dd");
    }
};

public String formatDate(Date date) {
    return format1.get().format(date);
}
Evgeniy Dorofeev
  • 133,369
  • 30
  • 199
  • 275
  • 1
    Do people do that? If you (the original l poster) does not understand ThreadLocals properly I would recommend not using them. I would maybe consider FastDateFormat from Commons Lang, or DateTimeFormat from the JodaTime library. Here is a long and interesting thread on the subject.. http://jsr166-concurrency.10961.n7.nabble.com/Threadlocals-and-memory-leaks-in-J2EE-td3960.html – JohnMark13 Sep 03 '13 at 10:52
  • 1
    @JohnMark13 : Yes, people do that. I also [recommend](https://stijndewitt.wordpress.com/2014/07/28/how-javas-text-formats-can-subtly-break-your-code/) it. How is he not understanding ThreadLocals properly? Joshua Bloch, author of Effective Java says on your link: "This thread is littered with misinformation. [..] There is nothing inherently wrong with thread locals: They do not cause memory leaks. They are not slow.". The discussion is about bugs in Tomcat and some other apps that use thread pools and have implementation issues with ThreadLocals. They can and should be fixed in those apps. – Stijn de Witt Aug 27 '14 at 17:29
  • @StijndeWitt Because his question is [paraphrased] "I do not know how to do this using Thread Local". See also, "otherwise it will leak the memory .why do we want these references after the current thread work has done", which shows a lack of understanding. Agree should be fixed in the containers, but you firstly need to understand what they are and secondly how they might impact your project is you use them incorrectly. Or, just copy a code snippet from SO and don't worry about understanding what it does. – JohnMark13 Aug 28 '14 at 09:14
  • 1
    True... I was confused by the comment being on this answer and not on the question itself but you are right... Only use something if you understand the effects it will have. – Stijn de Witt Aug 29 '14 at 07:49
11

ThreadLocal in Java is a way to achieve thread-safety apart from writing immutable classes. Since SimpleDateFormat is not thread safe, you can use a ThreadLocal to make it thread safe.

class DateFormatter{

    private static ThreadLocal<SimpleDateFormat> outDateFormatHolder = new ThreadLocal<SimpleDateFormat>() {
    @Override
    protected SimpleDateFormat initialValue() {
        return new SimpleDateFormat("MM/dd/yyyy");
    }
};

private static ThreadLocal<SimpleDateFormat> inDateFormatHolder = new ThreadLocal<SimpleDateFormat>() {
    @Override
    protected SimpleDateFormat initialValue() {
        return new SimpleDateFormat("yyyyMMdd");
    }
};

public static String formatDate(String date) throws ParseException { 
    return outDateFormatHolder.get().format(
            inDateFormatHolder.get().parse(date));
}        
}
Richie
  • 9,006
  • 5
  • 25
  • 38
  • Thanks Richie, But your class not working saying class body,field declaration not completed.i added extra closing braces but still no luck.and also how to remove these threadlocal references once calll is over. – user2680017 Sep 03 '13 at 11:17
  • check now. I have added the braces now. – Richie Sep 03 '13 at 11:54
  • otherwise it will leak the memory .why do we want these references after the current thread work has done. – user2680017 Sep 03 '13 at 12:48
  • 1
    If you see the code - both the objects are static which means that it would be like singleton. As long as you are not creating ThreadLocal instances each time, you need not worry about memory leaks. But in case you are very particular - to remove references, you can manually call outDateFormatHolder.remove() and inDateFormatHolder.remove() from formatDate method. http://stackoverflow.com/questions/3869026/how-to-clean-up-threadlocals – Richie Sep 03 '13 at 15:19
  • "final Date date = format1.parse(tradeDate); final Date formattedDate = format2.parse(format2.format(date));" - date and formattedDate are the same - You can debug and check. If you need the date object then the first statement is enough - the date object is not stored with the format. If you want to print the date object again after your second statment, still you will need to call the format method. – Richie Sep 03 '13 at 15:26
1

Java-8+

The modern Date-Time classes introduced with Java-8 are thread-safe.

Demo:

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        DateTimeFormatter parser = DateTimeFormatter.ofPattern("uuuuMMdd", Locale.ENGLISH);
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/uuuu", Locale.ENGLISH);
        LocalDate date = LocalDate.parse("20130212", parser);
        String formattedString = date.format(formatter);
        System.out.println(formattedString);
    }
}

Output:

12/02/2013

Note that I prefer u to y with DateTimeFormatter.

Learn more about the modern Date-Time API from Trail: Date Time.

Arvind Kumar Avinash
  • 71,965
  • 6
  • 74
  • 110