• ThreadLocal的使用


    实现变量值的共享,可以使用public static变量的形式,这种形式修饰的变量在所有使用该变量的线程间都是共享的

    使用ThreadLocal也可以实现变量值的共享,这种共享旨在实现每个线程自己的变量共享

     1 public class Run {
     2     public static ThreadLocal threadLocal = new ThreadLocal();
     3 
     4     public static void main(String[] args) {
     5         if (threadLocal.get() == null){
     6             System.out.println("threadLocal中没有值");
     7             threadLocal.set("testValue");
     8             threadLocal.set("testValue2");
     9         }
    10         System.out.println(threadLocal.get());
    11         System.out.println(threadLocal.get());
    12     }
    13 }
    threadLocal中没有值
    testValue2
    testValue2

    threadLocal对象在第一次调用get()方法时返回null,然后通过调用set()方法赋值,赋值以最后一次为准

    本例中在main线程中执行,main线程相当于key,set的值是value

    ThreadLocal解决的是多线程之间的隔离性,不同线程有自己独立的值,不同线程的值可以放在ThreadLocal中进行保存

    ThreadLocal其实可以看做成全局存放数据的盒子,盒子中存放每个线程的私有数据,每个线程就是私有数据的标签


    验证线程变量的隔离性

    public class Utils {
        public static ThreadLocal threadLocal = new ThreadLocal();
    }

    --------------------------------------------------线程类--------------------------------------------------

    public class ThreadA extends Thread {
        @Override
        public void run() {
            try {
                for (int i = 0; i < 100; i++) {
                    Utils.threadLocal.set("ThreadA"+(i+1));
                    System.out.println("ThreadA get value = "+Utils.threadLocal.get());
                    Thread.sleep(200);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    -----------------------------------------------------
    public class ThreadB extends Thread {
        @Override
        public void run() {
            try {
                for (int i = 0; i < 100; i++) {
                    Utils.threadLocal.set("ThreadB"+(i+1));
                    System.out.println("ThreadB get value = "+Utils.threadLocal.get());
                    Thread.sleep(200);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    --------------------------------------------------测试类--------------------------------------------------

    public class Run {
        public static void main(String[] args) {
            try {
                ThreadA a = new ThreadA();
                ThreadB b = new ThreadB();
                a.start();
                b.start();
    
                for (int i = 0; i < 100; i++) {
                    Utils.threadLocal.set("main"+(i+1));
                    System.out.println("main get value = "+Utils.threadLocal.get());
                    Thread.sleep(200);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    --------------------------------------------------console--------------------------------------------------

    ........
    main get value = main96
    ThreadA get value = ThreadA96
    ThreadB get value = ThreadB96
    ThreadA get value = ThreadA97
    main get value = main97
    ThreadB get value = ThreadB97
    main get value = main98
    ThreadA get value = ThreadA98
    ThreadB get value = ThreadB98
    ThreadA get value = ThreadA99
    main get value = main99
    ThreadB get value = ThreadB99
    main get value = main100
    ThreadA get value = ThreadA100
    ThreadB get value = ThreadB100

    每个线程都向threadLocal对象中set数据值,但是每个线程都可以正确的取出各自设置的值

    第一次调用ThreadLocal的get方法返回的是null,如何使得第一次调用get返回不是null???使用一个继承ThreadLocal类的自定义类


    处理ThreadLocal第一次调用get()返回null

    案例1

    public class MyThreadLocal extends ThreadLocal {
        @Override
        protected Object initialValue() {
            return "请先设置值,再调用get方法";
        }
    }
    public class Run {
        public static MyThreadLocal threadLocal = new MyThreadLocal();
        public static void main(String[] args) {
            System.out.println(threadLocal.get());
        }
    }

    --------------------------------------------------console--------------------------------------------------

    请先设置值,再调用get方法

    案例2

    -----------------------------------------------------utils----------------------------------------------------

    public class MyThreadLocal extends ThreadLocal {
        @Override
        protected Object initialValue() {
            return new Date().getTime();
        }
    }
    public class Utils {
        public static MyThreadLocal threadLocal = new MyThreadLocal();
    }

    --------------------------------------------------线程类--------------------------------------------------

    public class MyThread extends Thread {
        @Override
        public void run() {
            try {
                for (int i = 0; i < 10; i++) {
                    System.out.println("MyThread线程中取值="+ Utils.threadLocal.get());
                    Thread.sleep(100);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    --------------------------------------------------测试类--------------------------------------------------

    public class Run {
        public static void main(String[] args) {
            try {
                for (int i = 0; i < 10; i++) {
                    System.out.println("main线程中取值="+ Utils.threadLocal.get());
                    Thread.sleep(100);
                }
                Thread.sleep(5000);
                MyThread thread = new MyThread();
                thread.start();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    --------------------------------------------------console--------------------------------------------------

    main线程中取值=1537495764646
    main线程中取值=1537495764646
    main线程中取值=1537495764646
    main线程中取值=1537495764646
    main线程中取值=1537495764646
    main线程中取值=1537495764646
    main线程中取值=1537495764646
    main线程中取值=1537495764646
    main线程中取值=1537495764646
    main线程中取值=1537495764646
    MyThread线程中取值=1537495770657
    MyThread线程中取值=1537495770657
    MyThread线程中取值=1537495770657
    MyThread线程中取值=1537495770657
    MyThread线程中取值=1537495770657
    MyThread线程中取值=1537495770657
    MyThread线程中取值=1537495770657
    MyThread线程中取值=1537495770657
    MyThread线程中取值=1537495770657
    MyThread线程中取值=1537495770657

    每个线程有自己各自的默认值


    InheritableThreadLocal类的使用

    InheritableThreadLocal类的作用是使得子线程可以继承父线程中的值

    -----------------------------------------------------utils----------------------------------------------------

    public class MyInheritableThreadLocal extends InheritableThreadLocal {
        @Override
        protected Object initialValue() {
            return new Date().getTime();
        }
    }
    -------------------------------------------------------------------------------
    public class Utils {
        public static MyInheritableThreadLocal threadLocal = new MyInheritableThreadLocal();
    }

    --------------------------------------------------线程类--------------------------------------------------

    public class MyThread extends Thread {
        @Override
        public void run() {
            try {
                for (int i = 0; i < 5; i++) {
                    System.out.println("MyThread线程中取值="+ Utils.threadLocal.get());
                    Thread.sleep(200);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    --------------------------------------------------测试类--------------------------------------------------

    public class Run {
        public static void main(String[] args) {
            try {
                for (int i = 0; i < 5; i++) {
                    System.out.println("main线程中取值="+ Utils.threadLocal.get());
                    Thread.sleep(200);
                }
                Thread.sleep(3000);
                MyThread thread = new MyThread();
                thread.start();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    --------------------------------------------------console--------------------------------------------------

    main线程中取值=1537496806863
    main线程中取值=1537496806863
    main线程中取值=1537496806863
    main线程中取值=1537496806863
    main线程中取值=1537496806863
    MyThread线程中取值=1537496806863
    MyThread线程中取值=1537496806863
    MyThread线程中取值=1537496806863
    MyThread线程中取值=1537496806863
    MyThread线程中取值=1537496806863

    可以发现MyThread和main中取得值是一样的,子线程继承了父线程的值

    修改MyThread.java,再次测试

    public class MyThread extends Thread {
        @Override
        public void run() {
            try {
                for (int i = 0; i < 5; i++) {
                    Utils.threadLocal.set(new Date().getTime());
                    System.out.println("MyThread线程中取值="+ Utils.threadLocal.get());
                    Thread.sleep(200);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    --------------------------------------------------console--------------------------------------------------

    main线程中取值=1537497153735
    main线程中取值=1537497153735
    main线程中取值=1537497153735
    main线程中取值=1537497153735
    main线程中取值=1537497153735
    MyThread线程中取值=1537497157740
    MyThread线程中取值=1537497157940
    MyThread线程中取值=1537497158140
    MyThread线程中取值=1537497158341
    MyThread线程中取值=1537497158542

    子线程自己设置值就用自己的值,自己没设置值就会使用从父线程继承的值

    子线程继承父线程的值时,可以对值做相应处理

    修改MyInheritableThreadLocal.java

    public class MyInheritableThreadLocal extends InheritableThreadLocal {
        @Override
        protected Object initialValue() {
            return new Date().getTime();
        }
    
        @Override
        protected Object childValue(Object parentValue) {
            return "从父线程继承值:"+parentValue;
        }
    }

    --------------------------------------------------console--------------------------------------------------

    main线程中取值=1537497472137
    main线程中取值=1537497472137
    main线程中取值=1537497472137
    main线程中取值=1537497472137
    main线程中取值=1537497472137
    MyThread线程中取值=从父线程继承值:1537497472137
    MyThread线程中取值=从父线程继承值:1537497472137
    MyThread线程中取值=从父线程继承值:1537497472137
    MyThread线程中取值=从父线程继承值:1537497472137
    MyThread线程中取值=从父线程继承值:1537497472137

    如果子线程取值时,父线程又发生变化会怎么样呢?

    修改测试类Run.java

    public class Run {
        public static void main(String[] args) {
            try {
                MyThread thread = new MyThread();
                thread.start();
                for (int i = 0; i < 5; i++) {
                    Utils.threadLocal.set(new Date().getTime());
                    System.out.println("main线程中取值="+ Utils.threadLocal.get());
                    Thread.sleep(200);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    --------------------------------------------------console--------------------------------------------------

    main线程中取值=1537498416687
    MyThread线程中取值=1537498416689
    main线程中取值=1537498416889
    MyThread线程中取值=1537498416689
    main线程中取值=1537498417089
    MyThread线程中取值=1537498416689
    main线程中取值=1537498417290
    MyThread线程中取值=1537498416689
    main线程中取值=1537498417490
    MyThread线程中取值=1537498416689

    如果子线程在取值的时候父线程的InheritableThreadLocal中的值发生变化,那么子线程取得的还是旧值

  • 相关阅读:
    .netcore利用DI实现级联删除
    识别手写数字增强版100%
    嗨!请查收这道有趣的面试题
    理解TCP/IP协议栈之HTTP2.0
    基于Redis的分布式锁和Redlock算法
    从生日悖论谈哈希碰撞
    Redis面试热点工程架构篇之数据同步
    Redis面试热点之底层实现篇(续)
    saltstack安装+基本命令
    25个iptables常用示例
  • 原文地址:https://www.cnblogs.com/qf123/p/9685418.html
Copyright © 2020-2023  润新知