• ThreadLocal


    当一个类只需要在全局只需要一份实例存在,可以使用单例模式实例该类,比如mybatis的错误日志打印类ErrorContext,现在利用饿汉模式实现一个单例类,这个类保证了程序每个地方拿到的实例都是同一个。

    public class ThreadLocalLearn {
        private static ThreadLocalLearn threadLocalLearn = new ThreadLocalLearn();
        private ThreadLocalLearn() {
            // 单例模式
        }
        public static ThreadLocalLearn instance() {
            return threadLocalLearn;
        }
    }

    这个类目前是线程安全的,但是当这个类含有私有属性,用来记录最终打印的内容时,这样的实现是线程不安全的。

    public class ThreadLocalLearn {
        // 线程不安全的单例模式
        private static ThreadLocalLearn threadLocalLearn = new ThreadLocalLearn();
    
        private String name = null;
        private Integer age = null;
    
        private ThreadLocalLearn() {
            // 单例模式
        }
    
        public static ThreadLocalLearn unSafeInstance() {
            return threadLocalLearn;
        }
    
    }

    一个线程设置name时,另一个线程可能同时设置了age,导致name和age并非同一个线程赋的值。

    而为了一个类在多线程中针对每个线程的单例模式实现,一种设计方法需要用到ThreadLocal,简要的来说,每个线程都有一个独立的对象区,而ThreadLocal就是给线程设置或者获取线程对象的方法。

    public class ThreadLocalLearn {
        // 线程安全的单例模式
        private static final ThreadLocal<ThreadLocalLearn> LOCAL = new ThreadLocal<>();
    
        private String name = null;
        private Integer age = null;
    
        private ThreadLocalLearn() {
            // 单例模式
        }
    
        public static ThreadLocalLearn safeInstance() {
            ThreadLocalLearn threadLocalLearn = LOCAL.get();
            if (threadLocalLearn == null) {
                threadLocalLearn = new ThreadLocalLearn();
                LOCAL.set(threadLocalLearn);
            }
            return threadLocalLearn;
        }
    }

    当ThreadLoal调用set方法时,会将实例出的ThreadLocalLearn对象绑定到当前线程上,get方法时会从当前线程获取这个对象,从而达到针对每个线程的单例作用,由于每个线程获取到的ThreadLocalLearn都是自身线程创建的,也就不存在name,age设置冲突问题。

    ThreadLocal的具体实现是:

      1.对每个Thread,都维护了一个Map(ThreadLocal.ThreadLocalMap),用于绑定ThreadLocal Set的实例集合

      2.ThreadLocal 调用Get方法时,首先获取当前线程(Thread.currentThread()),再获取ThreadLocalMap,像使用HashMap一样Get出对象(Key为ThreadLocal<T> 中的T, 比如ThreadLocalLearn)

      3. Set 与(2)类型,实现非常简单。

    ------------------------------------------------------------------------------------------------------------------------------------------------------------------

    完整例子代码:

    public class ThreadLocalLearn {
        // 线程不安全的单例模式
        private static ThreadLocalLearn threadLocalLearn = new ThreadLocalLearn();
        // 线程安全的单例模式
        private static final ThreadLocal<ThreadLocalLearn> LOCAL = new ThreadLocal<>();
    
        private String name = null;
        private Integer age = null;
    
        private ThreadLocalLearn() {
            // 单例模式
        }
    
        public static ThreadLocalLearn unSafeInstance() {
            return threadLocalLearn;
        }
    
        public static ThreadLocalLearn safeInstance() {
            ThreadLocalLearn threadLocalLearn = LOCAL.get();
            if (threadLocalLearn == null) {
                threadLocalLearn = new ThreadLocalLearn();
                LOCAL.set(threadLocalLearn);
            }
            return threadLocalLearn;
        }
    
        public ThreadLocalLearn personName(String personName) {
            this.name = personName;
            return this;
        }
    
        public ThreadLocalLearn personAge(Integer personAge) {
            this.age = personAge;
            return this;
        }
    
        @Override
        public String toString() {
            StringBuilder description = new StringBuilder();
            if (name != null) {
                description.append("|Name: ");
                description.append(this.name);
            }
    
            if (age != null) {
                description.append("|Age: ");
                description.append(this.age);
            }
    
            return description.toString();
        }
    
        public static void main(String[] args) {
            for (int i = 0; i < 100; i++) {
                // 线程不安全例子
                // Thread thread = new Thread(new UnsafeTester(i));
                // 线程安全例子
                Thread thread = new Thread(new SafeTester(i));
                thread.start();
            }
        }
    }
    
    
    class UnsafeTester implements Runnable {
        private Integer index;
    
        public UnsafeTester(Integer index) {
            this.index = index;
        }
    
        @Override
        public void run() {
            ThreadLocalLearn threadLocalLearn = ThreadLocalLearn.unSafeInstance();
            threadLocalLearn.personAge(index).personName(String.valueOf(index));
            System.out.println(threadLocalLearn.toString());
        }
    
    }
    
    
    class SafeTester implements Runnable {
        private Integer index;
    
        public SafeTester(Integer index) {
            this.index = index;
        }
    
        @Override
        public void run() {
            ThreadLocalLearn threadLocalLearn = ThreadLocalLearn.safeInstance();
            threadLocalLearn.personAge(index).personName(String.valueOf(index));
            System.out.println(threadLocalLearn.toString());
        }
    }

    参照:

      1. mybatis3 ErrorContext 实现。

  • 相关阅读:
    jvm 学习
    架构师
    关于javaScript堆、栈和队列
    ES6-对象的扩展-属性名表达式
    JS 中 ++i 和i++的区别
    递归算法讲解
    Ztree 仿淘宝树结构完美实现 移动 右键增删改
    jquery zTree异步加载实例
    【zTree】简单实例与异步加载实例
    win10中用命令行打开服务
  • 原文地址:https://www.cnblogs.com/syui-terra/p/10489529.html
Copyright © 2020-2023  润新知