Java笔记之ThreadLocal

Java笔记之ThreadLocal

在JDK官方API文档中关于ThreadLocal的描述是这样的:

该类提供了线程局部 (thread-local) 变量。这些变量不同于它们的普通对应物,因为访问某个变量(通过其 get 或 set 方法)的每个线程都有自己的局部变量,它独立于变量的初始化副本。ThreadLocal 实例通常是类中的 private static 字段,它们希望将状态与某一个线程(例如,用户 ID 或事务 ID)相关联。 在实际的使用中,ThreadLocal既可以实现数据共享又可以实现数据隔离,举个例子,当我们做一个数据库转账操作的时候,如果手动控制事务,那么就可以使用ThreadLocal,将connection和ThreadLocal绑定,每次要用到connection对象的时候从当前线程获取,从而保证在不同的地方使用的connection对象是同一个,以此来控制事务。
关于线程间的数据隔离我们写以下代码测试:

import java.util.Random;
import java.util.concurrent.TimeUnit;

/**
 * @Author Mr.Gibson
 * @Date 2020/6/8 10:29
 * @Version 1.0.0
 * @Description
 */
public class ThreadLocalTest implements Runnable{


    private ThreadLocal<Student> studentThreadLocal  =new ThreadLocal<>();
    @Override
    public void run() {
        /**
         *每个线程的ThreadLocal是同一个对象,那么他是如何实现同一个对象却存储了不同的student对象?
         * 点开ThreadLocal的set方法:
         *     public void set(T value) {
         *         Thread t = Thread.currentThread();
         *         ThreadLocalMap map = getMap(t);
         *         if (map != null)
         *             map.set(this, value);
         *         else
         *             createMap(t, value);
         *     }
         *     存在ThreadLocal里面的数据实际上是存在ThreadLocal里面的ThreadLocalMap里面的,而ThreadLocalMap的创建是根据当前线程创建的,
         *     换句话说,每一个线程都有一个对应的ThreadLocalMap用来存储数据,由此可以实现数据隔离
         *     ThreadLocalMap是ThreadLocal类的一个静态内部类,它实现了键值对的设置和获取(对比Map对象来理解),
         *     每个线程中都有一个独立的ThreadLocalMap副本,它所存储的值,只能被当前线程读取和修改。
         */
        System.out.println(studentThreadLocal);
        
        String currentThreadName = Thread.currentThread().getName();
        System.out.println("currentThread is :" + currentThreadName);
        Random random = new Random();
        int age = random.nextInt(100);
        System.out.println(currentThreadName + " is setting age:" + age);
        Student student = getStudent();
        System.out.println(student);//每个线程的student对象是不一样的,由此可暗示数据必被隔离
        student.setAge(age);
        System.out.println(currentThreadName + " is first get age :" + student.getAge());
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(currentThreadName + " is second get age" + student.getAge());
    }
    private Student getStudent() {
        Student student = studentThreadLocal.get();
        if (student == null){
            student = new Student();
            studentThreadLocal.set(student);
        }
        return student;

    }
    public static void main(String[] args) {
        ThreadLocalTest t1 = new ThreadLocalTest();
        new Thread(t1,"ThreadA").start();
        new Thread(t1,"ThreadA").start();
        new Thread(t1,"ThreadC").start();
        new Thread(t1,"ThreadD").start();
    }
}

class Student{
    int age;

    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}

在这里插入图片描述

从运行结果可以看出,线程中的ThreadLocal是同一个,当我们获取Student对象的时候都是通过get方法获取,然而却是不同的student对象,让我们点开
ThreadLocal的set方法:
    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }
	可以看出ThreadLocal中存储数据的是ThreadLocalMap,而这个map的创建是根据线程创建的,因此每个线程的map是不同的,因此可以实现数据隔离!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值