import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Random; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; /** * Created by zhangdongsheng on 15/5/13. */ public class ThreadLocalVsSynchronizedTest { private static final int ITERATIONS = 100000; private static final int NUM_THREADS = 15; private static final int BOOTSTRAP = 30; public static void main(String[] args) throws InterruptedException { //warming up test(new ThreadLocalFormatter(), 20); test(new SynchronizedFormatter(), 20); test(new NewInstanceFormatter(), 20); for (int i = 1; i <= NUM_THREADS; i++) { long threadLocalTime = 0, synchronizedTime = 0, newInstanceTime = 0, cloneTime = 0; for (int j = 0; j < BOOTSTRAP; j++) { synchronizedTime += test(new SynchronizedFormatter(), i); threadLocalTime += test(new ThreadLocalFormatter(), i); newInstanceTime += test(new NewInstanceFormatter(), i); cloneTime += test(new CloneFormatter(), i); } System.out.print(i + " " + TimeUnit.MILLISECONDS.convert(threadLocalTime, TimeUnit.NANOSECONDS)); System.out.print(" " + TimeUnit.MILLISECONDS.convert(synchronizedTime, TimeUnit.NANOSECONDS)); System.out.print(" " + TimeUnit.MILLISECONDS.convert(newInstanceTime, TimeUnit.NANOSECONDS)); System.out.println(" " + TimeUnit.MILLISECONDS.convert(cloneTime, TimeUnit.NANOSECONDS)); } } private static long test(Formatter formatter, int numThreads) throws InterruptedException { long start = System.nanoTime(); ExecutorService executor = Executors.newFixedThreadPool(numThreads); Executors.newFixedThreadPool(numThreads); for (int i = 0; i < numThreads; i++) { executor.execute(new FormatterWorker(formatter)); } executor.shutdown(); executor.awaitTermination(1, TimeUnit.DAYS); return System.nanoTime() - start; } private static class FormatterWorker implements Runnable { private final Formatter formatter; public FormatterWorker(Formatter formatter) { this.formatter = formatter; } @Override public void run() { Random rd = new Random(); for (int i = 0; i < ITERATIONS; i++) { String s = "2015-04-05 "; int h = rd.nextInt(24); int k1 = rd.nextInt(60); int k2 = rd.nextInt(60); s += (h < 10 ? "0" + h : h) + ":"; s += (k1 < 10 ? "0" + k1 : k1) + ":"; s += k2 < 10 ? "0" + k2 : k2; formatter.format(s); } } } private interface Formatter { Date format(String str); } private static class SynchronizedFormatter implements Formatter { private final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); @Override public synchronized Date format(String date) { try { return format.parse(date); } catch (ParseException e) { e.printStackTrace(); } return null; } } private static class ThreadLocalFormatter implements Formatter { private final ThreadLocal<SimpleDateFormat> format = new ThreadLocal<SimpleDateFormat>(); @Override public Date format(String date) { SimpleDateFormat dateFormat = this.format.get(); if (dateFormat == null) { dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); format.set(dateFormat); } try { return dateFormat.parse(date); } catch (ParseException e) { e.printStackTrace(); } return null; } } private static class NewInstanceFormatter implements Formatter { @Override public Date format(String date) { try { return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(date); } catch (ParseException e) { e.printStackTrace(); } return null; } } private static class CloneFormatter implements Formatter { private final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); @Override public Date format(String date) { try { return ((SimpleDateFormat)format.clone()).parse(date); } catch (ParseException e) { e.printStackTrace(); } return null; } } }