锁机制基础 & ThreadLocal-CSDN博客

32 阅读4分钟
package com.gch.test3;

/**
   i = i + 1这一行代码在底层有几步操作?
   答:在底层分成了三步操作。
 */
public class Test {
    public static void main(String[] args) {
        int i = 0;
        i = i + 1;
        System.out.println(i); // 1
    }
}

二. ThreadLocal 

ThreadLocal:线程隔离。

ThreadLocal可以实现每一个线程都有自己的专属本地变量。

隔离是一种需求,但是隔离的需求出现的本质并不是因为我要线程安全所以我要隔离,而是因为有些业务场景就是需要业务数据之间隔离,只不过隔离后恰好它线程安全。举例:比如你每个用户的请求,你是不是都要知道用户的信息,那你这个用户的信息存哪,是不是每个线程都要存一份。

  • ThreadLocal是每个线程相互隔离的,ThreadLocal可以实现线程之间的数据隔离

ThreadLocal的应用场景?

  • ThreadLocal用来解决数据库连接、Session管理等。

ThreadLocal的作用:
1. 线程隔离: ThreadLocal提供了一种在多线程环境下实现线程数据的隔离的方式,使每                              个线程都可以独立地的使用自己的专属本地变量,不受其它线程的干扰。
2. 线程上下文传递: ThreadLocal可以方便的在多个方法中传递线程相关的数据,而不需要                                        显式地通过参数传递。

ThreadLocal常用方法

ThreadLocal内存泄漏问题了解不?

  • ThreadLocalMap 的 Key 为 ThreadLocal 的弱引用,而 Value 是强引用。所以,如果ThreadLocal没有被外部强引用的情况下,在垃圾回收的时候,Key会被清理掉=>Key为null,而Value不会被清理掉,Value数据还存在,垃圾回收不掉
  • 这样一来,ThreadLocalMap中就会出现Key为null的Entry,假如我们不做任何措施的话,Value永远无法被GC回收,这个时候就可能会产生内存泄漏
  • ThreadLocalMap实现中已经考虑了这种情况,在使用完ThreadLocal方法后最好手动调用remove() 方法来清除ThreadLocal变量值,避免潜在地内存泄漏问题,特别是在线程池等长时间运行地环境中。

提问: 我们在定义ThreadLocal变量时定义的是static全局变量,既然是全局变量为什么               在不同的线程中去进行get和set还能做到线程隔离呢? ****--- ThreadLocal实现线程隔离             的底层原理?

  • ThreadLocal只是一个Key,每一个线程它是一个Thread对象,在Thread类中有一个私有字段/属性叫threadLocalsthreadLocals它是一个ThreadLocalMap对象,用于存储线程的局部变量每个线程都有一个ThreadLocalMap对象,ThreadLocalMap对象内部使用Entry数组来存储键值对,它的Key是ThreadLocal的引用,通过弱引用(WeakReference)来引用对应的ThreadLocal对象,这是为了避免内存泄漏的问题,因为 ThreadLocalMap 对 ThreadLocal 的引用是弱引用,当 ThreadLocal 对象没有其他强引用时,会被垃圾回收器回收。
  • Value是具体的线程局部变量的值/对应的是线程变量副本,Value是强引用

ThreadLocal它里面有一个静态内部类,叫做ThreadLocalMap

ThreadLocalMap 是 ThreadLocal 的静态内部类

  • ThreadLocalMap通过当前线程对象Thread来查找对应的ThreadLocalMap对象,并在该对象中根据ThreadLocal对象作为Key来存储和获取相应的值。

  • ThreadLocal本身是不存储值的, 它只是提供一个能查到这个值的Key给你。
  • ThreadLocal是包含在Thread中,而不是Thread包含在ThreadLocal中。

ThreadLocal实现线程隔离的Demo:

package com.gch.concurrent;

/**
 * ThreadLocal可以实现线程之间的数据隔离。
 * ThreadLocal的作用:
 *   1.线程隔离:ThreadLocal提供了一种在多线程环境下实现线程数据的隔离的方式,使每个线程都可以独立地的使用变量,不受其它线程的干扰。
 *   2.线程上下文传递:ThreadLocal可以方便的在多个方法中传递线程相关的数据,而不需要显式地通过参数传递。
 */
public class ThreadLocalDemo {
    public static final ThreadLocal<Integer> threadLocal = new ThreadLocal<>();
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(()->{
            System.out.println(threadLocal.get()); // null
            threadLocal.set(0);
            System.out.println(threadLocal.get()); // 0
        },"A");

        Thread t2 = new Thread(()->{
            System.out.println(threadLocal.get()); // null
            threadLocal.set(1);
            System.out.println(threadLocal.get()); // 1
        },"B");

        t1.start(); // 开启A线程
        t1.join(); // 插入线程/插队线程:哪个线程调用了join()方法,哪个线程就先执行完毕,再执行其它线程
        t2.start(); // 开启B线程

        System.out.println("main线程ID = " + Thread.currentThread().getId()); // 1

        System.out.println(threadLocal.get()); // null
    }
}

ThreadLocal在多个方法之间实现线程上下文数据的传递的Demo:

package com.gch.concurrent;

/**
   通过ThreadLocal在多个方法之间传递相同线程上下文的数据,而不需要显式的通过参数传递
   可以在复杂的业务逻辑中简化代码的编写和维护
 */
public class ThreadContextExample {
    public static ThreadLocal<String> threadLocal = new ThreadLocal<>();

    public static void main(String[] args) {
        /**
           设置线程上下文数据
         */
        threadLocal.set("Initial Value");

        // 在主线程中调用方法A
        methodA();

        threadLocal.remove(); // 清除线程上下文数据
    }

    public static void methodA(){
        String value = threadLocal.get(); // 获取线程上下文数据
        System.out.println("Value in methodA: " + value);

        // 在方法A中调用方法B
        methodB();
    }

    public static void methodB(){
        String value = threadLocal.get(); // 获取线程上下文数据
        System.out.println("Value in methodB: " + value);

        // 在方法B中调用方法C
        methodC();
    }

    public static void methodC(){
        String value = threadLocal.get(); // 获取线程上下文数据
        System.out.println("Value in methodC: " + value);
    }
}