第一种: 基于ThreadLocal解决,关于ThreadLocal本人有以下的理解以及应用场景: 1.不同线程之前数据的隔离性 2.同一线程上下文之间数据的共享 3.作为一个容器,持有共享数据的副本 应用场景: 1.token的封装 即:
// private static ThreadLocal<Map<Class<?>, Object>> context = new InheritableThreadLocal<>(); // private static ThreadLocal<Integer> threadLocal = ThreadLocal.withInitial(() -> 1); // // /** // * 把参数设置到上下文map中 // */ // public static void put(Object object) { // Map<Class<?>, Object> map = context.get(); // if (null == map) { // map = new HashMap<>(); // context.set(map); // } // if (object instanceof Enum) { // map.put(object.getClass().getSuperclass(), object); // } else { // map.put(object.getClass(), object); // } // } // // /** // * 获取上下文的内容 // */ // public static <T> T get(Class<T> c) { // Map<Class<?>, Object> map = context.get(); // if (null == map) { // return null; // } // return (T) map.get(c); // } // // /** // * 清空ThreadLocal的数据 // */ // public static void clean() { // context.remove(); // }
第二:
数据库连接的处理
public class ThreadLocal_sdf { /** * Supplier<? extends S> supplier * supplier数据的创造者,即可以是数据容器的创造者,也可以是具体数据的提供者,是一个函数式接口 * * @FunctionalInterface public interface Supplier<T> { * <p> * /** * * Gets a result. * * * * @return a result * T get(); 实现数据的隔离 */ private static final ThreadLocal<SimpleDateFormat> FMT = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy" + "-MM-dd HH:mm:ss")); private static final AtomicInteger count = new AtomicInteger(0); public static String format(Date date) { return FMT.get().format(date); } public static Date parse(String str) throws ParseException { return FMT.get().parse(str); } public static void main(String[] args) throws ParseException { /** * * 注意: * 这个是每一个线程都实例化一个日期对象,这个肯定是线程安全的,不存在资源竞争的问题 * for (int i = 0; i < 100; i++) { * new Thread(() -> { * SimpleDateFormat formater = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); * Date now = new Date(); * String format = formater.format(now); * try { * Date parse = formater.parse(format); * } catch (ParseException e) { * e.printStackTrace(); * } * }).start(); */ for (int i = 0; i < 100; i++) { new Thread(() -> { Date now1 = new Date(); String format = format(now1); count.getAndIncrement(); System.out.println("字符串日期" + format + "线程名称-----" + Thread.currentThread().getName() + "线程数量" + count.get()); try { Date parse = parse(format); System.out.println("日期对象" + parse + "线程名称-----" + Thread.currentThread().getName()); } catch (ParseException e) { e.printStackTrace(); } }).start(); } } }
第二:日期的处理,利用传统的方式进行处理
1.利用synchronized处理
2.利用ReenTeentLock处理,二者的原理是一样的
/** * 当用static +final 修饰的时候,可以说是一种单例模式 */ private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); /** * 将日期对象转换为字符串 * * @param date * @return */ public static synchronized String format(Date date) { return sdf.format(date); } /** * 字符串日期转换为日期对象 * static 修饰的是类锁 * 不是实例锁---锁颗粒化 * * @param date * @return * @throws ParseException */ public static synchronized Date parse(String date) throws ParseException { return sdf.parse(date); } public static void main(String[] args) { for (int i = 0; i < 100; i++) { new Thread(() -> { /** * 如果每一个线程都各自实例化一个日期对象,那么1.做不到复用,2.多线程环境下与线程安全没关系 */ // SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); //执行子任务,也就是开启的一个子线程,在此相当于run方法中的业务代码 Date date = new Date(); String format = format(date); try { Date parse = parse(format); } catch (ParseException e) { e.printStackTrace(); } }).start(); } }
可以参考以下文章的说明