ThreadLocal介绍及使用

ThreadLocal可以使每个线程保存自己的一些私有数据,起到线程隔离的作用。打个比方,可以将其比喻成大型超市里的公共储物柜,每个人都可以使用,但是储物柜又分为好多小箱子来保证每个顾客有属于自己的存储空间,只能存取自己的物品。

下面来看看ThreadLocal的使用。

1.ThreadLocal.get()和ThreadLocal.set()

创建一个ThreadLocalDemo.java类

public class ThreadLocalDemo {
    public static ThreadLocal t1 = new ThreadLocal();
    public static void main(String[] args){
        if(t1.get()== null){
            System.out.println("还没有放入数据");
            t1.set("已放入值");
            t1.set("再次放入覆盖");
        }
        System.out.println(t1.get());
        System.out.println(t1.get());
    }
}

运行后,可以看到结果如下:
这里写图片描述

从运行结果可以看到,第一次调用t1对象的get()返回的是null,通过调用set()后赋值后并取出打印到控制台上,并且从代码中看到,第二次set()方法赋值会覆盖掉第一次的值,所以get取出的值为最后一次set的值。

ThreadLocal解决的是变量在不同线程间的隔离性,也就是不同线程拥有自己的值,不同线程的值是可以放到ThreadLocal类中进行保存的。


2.验证线程变量的隔离性

首先创建一个全局的ThreadLocal类:

public class Tool {
    public static ThreadLocal t1 = new ThreadLocal();
}

创建两个自定义线程类:

public class ThreadA extends Thread {
    @Override
    public void run() {
        try {
            for (int i = 0; i < 10; i++){
                Tool.t1.set("ThreadA+"+(i+1));
                System.out.println("ThreadA获取的值为 "+ Tool.t1.get());
                Thread.sleep(100);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

public class ThreadB extends Thread {
    @Override
    public void run() {
        try {
            for (int i = 0; i < 10; i++){
                Tool.t1.set("ThreadB+"+(i+1));
                System.out.println("ThreadB获取的值为 "+ Tool.t1.get());
                Thread.sleep(100);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

测试类:

public class ThreadTest {
    public static void main(String[] args){
        ThreadA a = new ThreadA();
        ThreadB b = new ThreadB();
        a.start();
        b.start();
        try {
            for (int i = 0; i < 10; i++){
                Tool.t1.set("Main+"+(i+1));
                System.out.println("Main获取的值为 "+ Tool.t1.get());
                Thread.sleep(100);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

运行后,可以看到结果如下:
这里写图片描述

从测试中可以看到,虽然运行了3个线程,但是每个线程还是可以从ThreadLocal中取出自己的数据。

在文章开始的代码中,在还没有调用ThreadLocal.set()方法赋值时第一次调用get方法,返回结果为null,那么如何使在第一次调用get方法的时候不返回空,而有默认的取值呢。方法是,创建一个类继承自ThreadLocal并重写initialValue()方法。

代码示例如下:

public class ThreadLocalExt extends ThreadLocal {
    @Override
    protected Object initialValue() {
        return "默认取值,第一次调用不再返回空";
    }
}

这里就不再展示运行结果了。

`ThreadLocal`是Java中提供的一种线程局部变量(Thread Local Variable)机制,它为每个线程创建了一个独立的副本,因此在多线程环境下,每个线程都有自己的变量值,不会相互干扰。`ThreadLocal`的主要作用是在不使用synchronized关键字的情况下实现线程间的局部数据隔离。 以下是`ThreadLocal`的主要特点和用法: 1. **自动绑定**:当在一个线程中对`ThreadLocal`变量赋值时,这个值会自动绑定到当前线程上,其他线程无法访问该值,除非它们也显式地为这个变量赋值。 2. **线程安全**:`ThreadLocal`本身并不保证线程安全,因为它不提供同步机制。如果需要在多个线程之间共享某个值,需要开发者自己管理同步。 3. **清除值**:每个线程结束时,其关联的`ThreadLocal`变量会被自动清零,如果需要手动清除,可以调用`ThreadLocal.remove()`方法。 4. **静态方法访问**:`ThreadLocal`提供了一个静态方法`get()`, 用于获取当前线程的副本值,如果没有为该线程设置过值,则返回`initialValue`参数的默认值。 ```java ThreadLocal<String> threadLocal = new ThreadLocal<>(); // 在一个线程中设置并读取值 threadLocal.set("Hello"); String value = threadLocal.get(); // 在当前线程中,value等于"Hello" // 在另一个线程中,值是空的或默认值 threadLocal.set("World"); value = threadLocal.get(); // 在这个线程中,value等于"World" ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值