001/* 002 * Copyright (c) 2010-2024 Mark Allen, Norbert Bartels. 003 * 004 * Permission is hereby granted, free of charge, to any person obtaining a copy 005 * of this software and associated documentation files (the "Software"), to deal 006 * in the Software without restriction, including without limitation the rights 007 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 008 * copies of the Software, and to permit persons to whom the Software is 009 * furnished to do so, subject to the following conditions: 010 * 011 * The above copyright notice and this permission notice shall be included in 012 * all copies or substantial portions of the Software. 013 * 014 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 015 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 016 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 017 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 018 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 019 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 020 * THE SOFTWARE. 021 */ 022package com.restfb.util; 023 024import java.lang.ref.SoftReference; 025import java.text.DateFormat; 026import java.text.SimpleDateFormat; 027import java.util.HashMap; 028import java.util.Map; 029import java.util.TimeZone; 030 031/** 032 * a DateFormat strategy that returns a cached SimpleDateFormat instance. 033 * <p> 034 * For every format string an instance of the SimpleDateFormat is saved on a per thread base, so the SimpleDateFormat 035 * instance is reused and you get an major speedup. 036 * <p> 037 * Attention: to prevent a possible memory leak while using this strategy you have to clean up the inner ThreadLocal 038 * with the {@code clearThreadLocal} method. 039 * 040 * @since 1.7.0 041 */ 042public class CachedDateFormatStrategy implements DateFormatStrategy { 043 044 @Override 045 public DateFormat formatFor(String format) { 046 return SimpleDateFormatHolder.formatFor(format); 047 } 048 049 public void clearThreadLocal() { 050 SimpleDateFormatHolder.clearThreadLocal(); 051 } 052 053 private static final class SimpleDateFormatHolder { 054 055 private static final ThreadLocal<SoftReference<Map<String, SimpleDateFormat>>> THREADLOCAL_FORMATTER_MAP = 056 ThreadLocal.withInitial(() -> new SoftReference<>(new HashMap<>())); 057 058 private static SimpleDateFormat formatFor(String pattern) { 059 SoftReference<Map<String, SimpleDateFormat>> ref = THREADLOCAL_FORMATTER_MAP.get(); 060 Map<String, SimpleDateFormat> formatterMap = ref.get(); 061 return formatterMap.computeIfAbsent(pattern, SimpleDateFormatHolder::createSDF); 062 } 063 064 private static SimpleDateFormat createSDF(String pattern) { 065 SimpleDateFormat sdf = new SimpleDateFormat(pattern); 066 sdf.setTimeZone(TimeZone.getTimeZone("UTC")); 067 return sdf; 068 } 069 070 private static void clearThreadLocal() { 071 THREADLOCAL_FORMATTER_MAP.remove(); 072 } 073 } 074 075}