When and How to use Java ThreadLocal class?
Q. What is a ThreadLocal class?
A. ThreadLocal is a handy class for simplifying development of thread-safe concurrent programs by making the object stored in this class not sharable between threads. ThreadLocal class encapsulates non-thread-safe classes to be safely used in a multi-threaded environment and also allows you to create per-thread-singleton.
Q. Are there any alternatives to using an object or resource pool to conserve memory in Java?
A. Yes, you can use a ThreadLocal object to create an object per thread. This approach is useful when creation of a particular object is not trivial and the objects cannot be shared between threads. For example, java.util.Calendar and java.text.SimpleDateFormat. Because these are heavy objects that often need to be set up with a format or locale, it’s very tempting to create it with a static initializer and stick the instance in a static field. Both of these classes use internal mutable state when doing date calculations or formatting/parsing dates. If they are called from multiple threads at the same time, the internal mutable state will most likely do unexpected things and give you wrong answers. In simple terms, this will cause thread-safety issues that can be very hard to debug.
Q. Are SimpleDateFormat and DecimalFormat classes thread-safe in Java?
A. No.
Q. How will you you use them in a thread-safe manner?
A. Declare it either as a local variable or use the anonymous ThreadLocal inner class if you want to use it across a number of different methods within the class as shown below.
package test.example; import java.math.BigDecimal; import java.text.DateFormat; import java.text.DecimalFormat; import java.text.NumberFormat; import java.text.SimpleDateFormat; import java.util.Date; public class InvestmentBalance { private static final ThreadLocal<NumberFormat> PERCENT_FORMAT = new ThreadLocal<NumberFormat>() { @Override protected NumberFormat initialValue() { return new DecimalFormat("###.##"); } }; private static final ThreadLocal<NumberFormat> DOLLAR_FORMAT = new ThreadLocal<NumberFormat>() { @Override protected NumberFormat initialValue() { return new DecimalFormat("$#,###.####"); } }; private static final ThreadLocal<DateFormat> DATE_FORMAT = new ThreadLocal<DateFormat>() { @Override protected DateFormat initialValue() { return new SimpleDateFormat("dd/MMM/yyyy"); } }; public String getPercentageOfInvAmount(BigDecimal amount) { return PERCENT_FORMAT.get().format(amount.doubleValue()) + "%"; } public String getDollarInvAmount(BigDecimal amount) { return DOLLAR_FORMAT.get().format(amount.doubleValue()); } public String getFormattedExpiryDate(Date date) { return DATE_FORMAT.get().format(date); } }
The class with the main method
package test.example; import java.math.BigDecimal; import org.joda.time.DateTime; import static java.lang.System.out; public class InvestmentBalanceTest { private static final DateTime dt; static { dt = new DateTime(2005, 3, 26, 12, 0, 0, 0); } public static void main(String[] args) { InvestmentBalance ib = new InvestmentBalance(); BigDecimal percent = new BigDecimal(35.479); percent.setScale(2, BigDecimal.ROUND_HALF_EVEN); BigDecimal amount = new BigDecimal(3525.49423); amount.setScale(4, BigDecimal.ROUND_HALF_EVEN); out.println(ib.getPercentageOfInvAmount(percent)); out.println(ib.getDollarInvAmount(amount)); out.println(ib.getFormattedExpiryDate(dt.toDate())); } }
Output:
35.48% $3,525.4942 26/Mar/2005
Labels: Coding, Multi-threading
0 Comments:
Post a Comment
Subscribe to Post Comments [Atom]
<< Home