【多线程】Java多线程基础(18)- 使用ThreadLocal

ThreadLocal

什么是ThreadLocal

ThreadLocal 是 Java 中的一个线程本地变量,它为每个线程提供了一个独立的变量副本,以避免多个线程之间的干扰和冲突。在使用 ThreadLocal 时,每个线程可以独立地访问和修改自己的变量副本,而不会影响其他线程的变量副本。

比如: 一个线程为一个用户服务, 每个用户的信息不同,而每个线程都会使用,因此,我们需要给每个线程添加本地变量(ThreadLocal)。

ThreadLocal的作用

ThreadLocal 的作用在于解决多线程并发访问共享变量时出现的线程安全问题。在多线程环境中,如果多个线程同时访问同一个共享变量,就会出现数据竞争和不一致的问题,从而导致程序的错误和异常。为了解决这个问题,我们可以将共享变量转化为每个线程独立的副本,使用 ThreadLocal 存储这些副本,从而避免多个线程之间的干扰和冲突。

ThreadLocal 的使用场景有很多,比如:

  • 数据库连接管理:在多线程环境中,每个线程需要独立地获取和释放数据库连接,可以使用 ThreadLocal 存储每个线程的连接对象。
  • 请求上下文传递:在 Web 应用程序中,每个请求都有自己的上下文,可以使用 ThreadLocal 存储请求上下文的信息,以便在整个请求处理过程中进行访问。
  • 日志跟踪:在分布式系统中,多个线程可能同时访问同一个日志文件,可以使用 ThreadLocal 存储每个线程的日志副本,从而避免日志信息的干扰和冲突。

需要注意的是,ThreadLocal 在使用时需要注意避免内存泄漏和不必要的资源浪费。由于每个线程都会有自己的变量副本,因此在多线程并发执行时,需要注意变量的访问和修改顺序,以避免出现不一致和冲突的情况。

具体怎么使用

使用 ThreadLocal 的一般步骤如下:

  1. 创建一个 ThreadLocal 对象。可以使用泛型来指定变量的类型。
ThreadLocal<String> threadLocal = new ThreadLocal<>();
  1. 在需要使用线程本地变量的地方,使用 ThreadLocal 对象的 set() 方法设置该线程的变量副本的值。可以使用 get() 方法获取该值。
threadLocal.set("value");
String value = threadLocal.get();
  1. 在需要清理线程本地变量的地方,使用 ThreadLocal 对象的 remove() 方法清理该线程的变量副本。
threadLocal.remove();

下面是一个示例,演示如何使用 ThreadLocal 存储线程本地变量的值:

public class ThreadLocalExample {
    // 创建ThreadLocal对象
    private static final ThreadLocal<String> threadLocal = new ThreadLocal<>();

    public static void main(String[] args) throws InterruptedException {
        ExecutorService executor = Executors.newFixedThreadPool(10);

        for (int i = 0; i < 10; i++) {
            executor.execute(() -> {
                // 为其设置值 
                threadLocal.set(Thread.currentThread().getName());
                System.out.println(threadLocal.get());
                // 记得移除变量,毕竟该线程可能会分配给其他任务使用。
                threadLocal.remove();
            });
        }

        executor.shutdown();
        executor.awaitTermination(10, TimeUnit.SECONDS);
    }
}

在这个例子中,我们创建了一个大小为 10 的线程池,并向其中提交了 10 个任务。在每个任务中,我们使用 threadLocal.set() 方法设置当前线程的变量副本的值为线程的名称,然后使用 threadLocal.get() 方法获取该值并打印。最后,我们使用 threadLocal.remove() 方法删除当前线程的变量副本。

需要注意的是,ThreadLocal 通常会占用一定的内存空间,因此在使用时需要注意避免内存泄漏和不必要的资源浪费。同时,由于每个线程都会有自己的变量副本,因此在多线程并发执行时,需要注意变量的访问和修改顺序,以避免出现不一致和冲突的情况。

总的来说,ThreadLocal 是一个非常有用的工具,可以帮助我们在多线程并发执行时,实现线程本地变量的存储和访问,从而避免多个线程之间的干扰和冲突。但是,在使用 ThreadLocal 时,我们需要注意避免内存泄漏和不必要的资源浪费,同时需要注意变量的访问和修改顺序,以确保程序的正确性和稳定性。

上面的例子是存储一个变量,如果要存储多个可以多new 几个threadLocal对象。

我们每次通过get()获得的都是同一个变量

ThreadLocal浅解

ThreadLocal实际上是通过ThreadLocalMap来实现的。

每个线程都有一个自己的ThreadLocalMap,用来存储该线程的所有线程局部变量。

ThreadLocal的工作原理是:

  1. ThreadLocal维护了一个ThreadLocalMap
  2. 当调用threadLocal.set(value)时,这个value会存储到当前线程的ThreadLocalMap中
  3. 当调用threadLocal.get()时,从当前线程的ThreadLocalMap中获取value

ThreadLocalset()方法:

public void set(T value) {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null) {
        map.set(this, value);
    } else {
        createMap(t, value);
    }
}

先获得当前线程,然后获得当前线程的ThreadMap,再把自己和对应的值存入map,这样就实现了每个线程都拥有自己的threadlocal副本。

© 版权声明
THE END
喜欢就支持一下吧
点赞0

Warning: mysqli_query(): (HY000/3): Error writing file '/tmp/MYLSyd4n' (Errcode: 28 - No space left on device) in /www/wwwroot/583.cn/wp-includes/class-wpdb.php on line 2345
admin的头像-五八三
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

图形验证码
取消
昵称代码图片