zoukankan      html  css  js  c++  java
  • 6.22 Java多线程ThreadLocal

    6.22 Java多线程ThreadLocal

    线程变量的特点

    • 多线程环境下,每个线程都有自己的数据

    • 一个线程的局部变量只有自己能看见,不会影响其他线程(使用局部变量比使用其他变量好)

    ThreadLocal的特点

    • ThreadLocal能够放一个线程级别的变量

    • 本身能够被多个线程共享使用,又能达到线程安全的目的

    • 在多线程环境下保证成员变量的安全

    常用方法:

    get/set/initialValue(初始化)方法

    JDK建议ThreadLocal定义为private static

    ThreadLocal常用的地方(内部存储结构类似于Map)

    • 为每一个线程绑定一个数据库连接(每一个线程有一个数据库连接)、HTTP请求、用户身份信息等

      • Hibernate的Session 工具类HibernateUtil

      • 通过不同的线程对象设置Bean属性,保证各个线程Bean对象的独立性

    • 每个线程拥有一个ThreadLocal

      • ThreadLocal内部的存储结构类似于Map

        • key是线程信息

        • value是对应的存储内容

        • 这样可以达到每个线程的数据相互独立,又可以共享一块大的区域。达到在多线程环境下保证成员变量的安全。

    ThreadLocal的实例demo
    package thread.rearrangement;

    /**
    * ThreadLocal:每个线程自身的存储区域(局部)
    * get/set/initialValue
    * @since JDK 1.8
    * @date 2021/6/22
    * @author Lucifer
    */
    public class ThreadLocalTestNo1 {

       /*声明类属性*/
    //   private static ThreadLocal<Integer> threadLocal = new ThreadLocal<>();

       /*更改初始值--->创建threadlocal的子类,重写initialValue*/
    //   private static ThreadLocal<Integer> threadLocal = new ThreadLocal<>(){
    //       protected Integer initialValue(){
    //           return 200; //初始化的值就更改成了200
    //       };
    //   };

       /*lambda表达式更改初始值*/
    //   private static ThreadLocal<Integer> threadLocal = ThreadLocal.withInitial(() -> {
    //       return 200;
    //   });

       /*更加简化代码*/
       private static ThreadLocal<Integer> threadLocal = ThreadLocal.withInitial(() -> 200);

       /*
       这样就开辟了一个大的存储空间
       每来一个线程都会自动开辟一个区域
       这些开辟的空间都会在大的存储空间内
        */

       public static void main(String[] args) {
           System.out.println(Thread.currentThread().getName() + "--->" + threadLocal.get());
           /*因为是整数,所以默认值是Null,不是零*/

           /*设置值*/
           threadLocal.set(99);
           System.out.println(Thread.currentThread().getName() + "--->" + threadLocal.get());

           /*
           现在所有的存储区域属于主线程main
            */

           /*实例化线程内部类*/
           new Thread(new MyRun()).start();
      }

       /**
        * 写一个内部类,实现Runnable接口
        * 线程类
        */
       public static class MyRun implements Runnable{

           /*重写run方法*/
           @Override
           public void run(){

               /*设置个随机数值*/
               threadLocal.set((int)(Math.random() * 99));

               /*获取值*/
               System.out.println(Thread.currentThread().getName() + "--->" + threadLocal.get());

          }
      }
    }
    /*
    每一个线程拥有自己的一个大的空间,里面存储的是自己的数据,大家相互不影响
    */
    ThreadLocal修改属性变量的实例demo
    package thread.rearrangement;

    /**
    * 每个线程存储自己的数据,更改不会影响其他线程
    * @since JDK 1.8
    * @date 2021/6/23
    * @author Lucifer
    */
    public class ThreadLocalTestNo2 {

       /*更加简化代码*/
       private static ThreadLocal<Integer> threadLocal = ThreadLocal.withInitial(() -> 1);

       /*
       这样就开辟了一个大的存储空间
       每来一个线程都会自动开辟一个区域
       这些开辟的空间都会在大的存储空间内
        */

       public static void main(String[] args) {
           for (int i=0; i<5; i++){
               new Thread(new MyRun()).start();
          }
      }

       /**
        * 写一个内部类,实现Runnable接口
        * 线程类
        */
       public static class MyRun implements Runnable{

           /*重写run方法*/
           @Override
           public void run(){

               /*获取当前线程的值*/
               Integer left = threadLocal.get();
               /*
               get方法的作用:
               返回当前线程的此线程局部变量的副本中的值
                */

               /*获取值*/
               System.out.println(Thread.currentThread().getName() + "得到了--->" + left);

               /*操作资源数*/
               threadLocal.set(left-1);

               /*再次打印*/
               System.out.println(Thread.currentThread().getName() + "还剩下--->" + threadLocal.get());

          }
      }
    }
    ThreadLocal调用分析
    package thread.rearrangement;

    /**
    * 分析ThreadLocal环境
    * @since JDk 1.8
    * @date 2021/6/23
    * @author Lucifer
    */
    public class ThreadLocalTestNo3 {

       /*创建ThreadLocal存储空间*/
       private static ThreadLocal<Integer> threadLocal = ThreadLocal.withInitial(() -> 1);

       public static void main(String[] args) {
           new Thread(new MyRun()).start();
           new Thread(new MyRun()).start();
      }

       /**
        * 创建一个内部线程类
        */
       public static class MyRun implements Runnable{

           /*写一个构造器*/
           public MyRun(){
               threadLocal.set(-100);
               System.out.println(Thread.currentThread().getName() + "--->" + threadLocal.get());
          }

           /*重写Runnable接口的run方法*/
           @Override
           public void run(){
               System.out.println(Thread.currentThread().getName() + "--->" + threadLocal.get());
          }
      }
    }
    InheritableThreadLocal拷贝线程数据实例
    package thread.rearrangement;

    /**
    * InheritableThreadLocal:继承上下文、环境的数据、起点
    * @since JDK 1.8
    * @date 2021/6/23
    * @author Lucifer
    */
    public class ThreadLocalTestNo4 {

       /*开辟ThreadLocal线程空间*/
       private static InheritableThreadLocal<Integer> threadLocal = new InheritableThreadLocal<>();

       public static void main(String[] args) {

           /*设置值*/
           threadLocal.set(2);

           /*线程属性变量*/
           System.out.println(Thread.currentThread().getName() + "--->" + threadLocal.get());

           /*修改拷贝的属性*/
           threadLocal.set(200);
           /*
           这样修改以后上面的线程就是初始设置的2
           下面的新的线程为现在设置的200
            */

           /*新建一个线程体*/
           new Thread(() -> {
               System.out.println(Thread.currentThread().getName() + "--->" + threadLocal.get());
          }).start();
           /*
           这是新的线程体的,他的值是null
           如果将ThreadLocal改为InheritableThreadLocal那么set值就会被延续到下一个线程体当中
           因为新建的线程由main线程开辟,所以会将数据拷贝一份给子线程
           这是拷贝不是共享,所以新的线程体还可以对属性进行修改
            */
      }
    }

     

    It's a lonely road!!!
  • 相关阅读:
    Django学习系列之Cookie、Session
    Django学习系列之CSRF
    Django学习系列之Form验证
    Django学习系列之结合ajax
    Logstash学习系列之插件介绍
    Logstash学习系列之基础介绍
    Kubernetes DNS安装配置
    Kubernetes网络配置
    kubernetes节点安装配置
    Kubernetes控制节点安装配置
  • 原文地址:https://www.cnblogs.com/JunkingBoy/p/14921576.html
Copyright © 2011-2022 走看看