多线程之_SimpleDateFormat线程不安全问题的两种解决方案

第一种:
  基于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();
        }
    }

可以参考以下文章的说明

https://www.jianshu.com/p/383e57cded1c

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值