ThreadLocal使用介绍

维持线程封闭性的一种常用方法是使用ThreadLocal,这是一个相对于线程来说是全局的变量。可以理解成线程的全局变量。ThreadLocal方法提供了get和set方法,这些方法为每个使用该变量的线程都存有一份独立的副本,因此get总是返回当前执行线程在调用set时设置的最新值。
ThreadLocal对象通常用于防止对可变的单实例变量或全局变量进行共享。例如,在单线程应用程序中可能会维持一个全局的数据库连接,并在程序启动时初始化这个数据库连接对象。从而避免在调用每个方法时,都需要传递一个Connction对象。由于JDBC的连接对象不一定是线程安全的,因此,当多线程应用程序在没有协同的情况下使用全局变量时,就不一定是线程安全的了。通过将jdbc的连接保存到ThreadLocal对象中,每个线程都会有一个自己的连接。
简单写了一个ThreadLocal的demo

package com.wsy.thread;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadLocalTest {
    // 创建一个线程池
    public static ExecutorService pool = Executors.newFixedThreadPool(5);
    // 创建一个线程的全局变量
    private static ThreadLocal<String> stringHolder = new ThreadLocal<String>();

    public static void main(String[] args) {

        //在线程外做的任何初始化都不会影响到线程
        stringHolder.set("test");
        // 启动一个线程将其赋值成test1
        pool.execute(new Runnable() {

            @Override
            public void run() {
                stringHolder.set("test1");
                System.out.println(stringHolder.get());
            }
        });

        // 再启动一个线程再次打印该值
        pool.execute(new Runnable() {

            @Override
            public void run() {
                // 预期打印的结果是test1,结果打印了null,原因就是ThreadLocal是线程相关的
                System.out.println(stringHolder.get());
            }
        });
    }
}

打印结果:
这里写图片描述
可以看到第二个线程打印的是null,并不是test,也不是test1,说明不论是在主线程中初始化ThreadLocal还是在其他线程中初始化ThreadLocal,都不会对某个线程的ThreadLocal对象的值造成影响。
这时候有人会问如果我想统一地做一个初始化,使得所有线程都可以使用怎么办?java当然考虑到了这一点,这一点可能是设计的源头之一。代码如下:

package com.wsy.thread;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadLocalTest {
    // 创建一个线程池
    public static ExecutorService pool = Executors.newFixedThreadPool(5);
    // 创建一个线程的全局变量
    private static ThreadLocal<String> stringHolder = new ThreadLocal<String>(){
        @Override
        protected String initialValue(){
            return "test5";
        }
    };

    public static void main(String[] args) {

        //在线程外做的任何初始化都不会影响到线程
        stringHolder.set("test");
        // 启动一个线程将其赋值成test1
        pool.execute(new Runnable() {

            @Override
            public void run() {
                stringHolder.set("test1");
                System.out.println(stringHolder.get());
            }
        });

        // 再启动一个线程再次打印该值
        pool.execute(new Runnable() {

            @Override
            public void run() {
                // 预期打印的结果是test1,结果打印了null,原因就是ThreadLocal是线程相关的
                System.out.println(stringHolder.get());
            }
        });
    }
}

打印结果如下:
这里写图片描述
可以看到此时打印出来的就是test5,我们可以通过重写initialValue方法来达到一次初始化。各个线程都有一个副本的情况。所谓师父领进门,修行在个人。知道了ThreadLocal的用法,具体什么时候使用,怎么用就是看个人的悟性了~

`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、付费专栏及课程。

余额充值