线程间数据传递之ThreadLocal、InheritableThreadLocal、TransmittableThreadLocal

线程间数据传递之ThreadLocal、InheritableThreadLocal、TransmittableThreadLocal

1、ThreadLocal介绍

spring 中基于 ThreadLocal 来实现事务。

多线程 访问同一个共享变量的时候容易出现并发问题,ThreadLocal是除了加锁这种同步方式之外的一种保证

规避多线程访问出现线程不安全的方法,当我们在创建一个变量后,如果每个线程对其进行访问的时候访问的都是

线程自己的变量这样就不会存在线程不安全问题。在实际多线程操作的时候,操作的是自己本地内存中的变量,从

而规避了线程安全问题。

ThreadLocal又叫做线程本地变量是为每一个Thread创建的一个变量的副本,每个线程都可以在内部访问到这个副

本。通过这种方式我们在一个线程的生命周期以内安全的访问这个变量,不用担心被其他线程所污染。这是它相对

于全局变量所带来的优势。

package com.example.threadlocalandother;

/**
 * @author tom
 */
public class ThreadLocalDemo {
   

    private ThreadLocal<Long> threadLocal = new ThreadLocal<>();

    private void fun1() {
   
        threadLocal.set(System.nanoTime());
        System.out.println("fun1:" + threadLocal.get());
        fun2();
    }

    private void fun2() {
   
        System.out.println("fun2:" + threadLocal.get());
        fun3();
    }

    private void fun3() {
   
        System.out.println("fun3:" + threadLocal.get());
        threadLocal.remove();
    }

    public static void main(String[] args) {
   
        ThreadLocalDemo demo = new ThreadLocalDemo();
        demo.fun1();
    }
}
# 程序输出
fun1:1511680153700
fun2:1511680153700
fun3:1511680153700

我们在先创建了一个本地变量threadLocal 在fun1中set值,在其余的方法中我们并没有通过方法传递的方式显示

的将值传递给其他方法,仅仅是通过threadLocal变量get的方式就可以获取到我们所需要的变量,从而实现了变量

的跨方法的传递。可能你觉得这样写没什么好处,我不用threadLocal直接用个全局变量照样可以实现数据的传

递,我们可以改造一下fun1方法。

package com.example.threadlocalandother;

/**
 * @author tom
 */
public class ThreadLocalDemo1 {
   

    private ThreadLocal<Long> threadLocal = new ThreadLocal<>();

    private void fun1() throws InterruptedException {
   
        threadLocal.set(System.nanoTime());
        System.out.println("fun1:" + threadLocal.get());
        final Thread t1 = new Thread(() -> {
   
            System.out.println("t1:" + threadLocal.get());
        }, "t1");
        t1.start();
        t1.join();
        fun2();
    }

    private void fun2() {
   
        System.out.println("fun2:" + threadLocal.get());
        fun3();
    }

    private void fun3() {
   
        System.out.println("fun3:" + threadLocal.get());
        threadLocal.remove();
    }

    public static void main(String[] args) throws InterruptedException {
   
        ThreadLocalDemo1 threadLocalDemo1 = new ThreadLocalDemo1();
        threadLocalDemo1.fun1();
    }
}
# 程序输出
fun1:3554613378000
t1:null
fun2:3554613378000
fun3:3554613378000

按照常理来想那么我们t1线程内也应该能获取到数据,但是结果大相径庭。实际上 threadLocal 对象只是作为了一

个 key,而真正存储数据的是每个线程自身的 thread 内持有的一个 ThreadLocalMap 的对象,而我们的 t1 线程

自然就不能获取到数据。如果使用后不 remove 可能会有内存泄漏的风险!

package com.example.threadlocalandother;

/**
 * @author tom
 */
public class ThreadLocalDemo2 {
   

    private ThreadLocal<Long> threadLocal = new ThreadLocal<>();

    public void run() {
   
        for (int i = 0; i < 10; i++) {
   
            new Thread(new Runnable() {
   
                @Override
                public void run() {
   
                    threadLocal.set(System.nanoTime());
                    Long aLong = threadLocal.get();
                    threadLocal.remove();
                    System.out.println(aLong);
                }
            }).start();
        }
    }

    public static void main(String[] args) {
   
        ThreadLocalDemo2 threadLocalDemo2 = new ThreadLocalDemo2();
        threadLocalDemo2.run();
    }
}
# 程序输出
3042907777600
3042907791300
3042908175100
3042908275900
3042908395900
3042908245300
3042908563900
3042908182800
3042908589200
3042908716700
package com.example.threadlocalandother;

/**
 * @author tom
 */
public class ThreadLocalDemo3 {
   

    /**
     * 创建ThreadLocal变量
     */
    private static final ThreadLocal<Integer> LOCAL_VARIABLE = new ThreadLocal<>();

    static void print(String str) {
   
        // 打印当前线程本地内存中localVariable变量的值
        System.out.println(str + ": " + LOCAL_VARIABLE.get());
        // 清除当前线程本地内存中的localVariable变量
        LOCAL_VARIABLE.remove();
    }

    public static void main(String[] args) {
   
        Thread t1 = new Thread(new Runnable() {
   
            @Override
            public void run() {
   
                // 设置线程1中本地变量的值
                LOCAL_VARIABLE.set(100);
                print("Thread 1");
                System.out.println("After remove: " + LOCAL_VARIABLE.get());
            }
        });

        Thread t2 = new Thread(new Runnable() {
   
            @Override
            public void run() {
   
                // 设置线程2中本地变量的值
                LOCAL_VARIABLE.set(200);
                print("Thread 2");
                System.out.println("After remove: " + LOCAL_VARIABLE.get());
            }
        });

        t1.start();
        t2.start();
    }
}
# 程序输出
Thread 1: 100
Thread 2: 200
After remove: null
After remove: null
package com.example.threadlocalandother;

/**
 * @author tom
 */
public class UserContext implements AutoCloseable {
   

    private final ThreadLocal<String> ctx = new ThreadLocal<>(
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值