前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >java面试必问之ThreadLocal

java面试必问之ThreadLocal

作者头像
xujjj
发布2019-08-15 18:40:45
4880
发布2019-08-15 18:40:45
举报
文章被收录于专栏:IT界的泥石流IT界的泥石流

JDK 1.2的版本开始提供java.lang.ThreadLocal,ThreadLocal为解决多线程程序的并发问题提供了一种新的思路。使用这个工具类可以很简洁地编写出优美的多线程程序。

当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。

在多线程环境下,每个线程都有自己的数据。一个线程使用自己的局部变量比使用全局变量好,因为局部变量只有线程自己能看见,不会影响其他线程。

从线程的角度看,目标变量就像是线程的本地变量,这也是类名中“Local”所要表达的意思。

上面陈述比较抽象,下面我们通过例子去说明。

public class ThreadLocalTest {
    //jdk建议ThreadLocal定义为private static
    private static ThreadLocal<Integer> threadLocal = new ThreadLocal<>();
}

这样,ThreadLocalTest该类中就有了一块名为threadLocal的大大的土地,里面有一个Integer类型的变量,默认值为null。

然后每个线程进来这块大土地里取值的时候,这块大土地会给该线程分一小亩地,还会把那个Integer类型的变量形成一个副本丢进这一小亩土地,其值还是为null。因此,每个线程进来取值的时候,取的都是属于自己那一小亩地的Integer类型的变量,互不干扰。

假设有thread-1和thread-2两个线程要从threadLocal取值,那按上述所讲,就是下图所示。

threadLocal这块大土地,两个线程都要从大土地中拿值,此时大土地分别给thread-1和thread-2两个线程各自分配两块互不相关的土地,并且里面的值是大土地的副本,因此thread-1取值是从属于thread-1的土地中取值,thread-2取值是从属于thread-2的土地中取值,所以它们两个线程互不干扰对方,每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。

ThreadLocal主要有三个方法,分别是get / set / initialValue.

首先我们看一下上述的这行代码。

private static ThreadLocal<Integer> threadLocal = new ThreadLocal<>();

因为threadLocal中的Integer类型没有赋初值,因此为null,现在我们想更改一下threadLocal的初始值,因此我们重写ThreadLocal类中的initialValue这个方法。把上面的那行代码改为如下这行代码。那么threadLocal中的Integer类型的变量的初始值就变成200了。

private static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>(){
        @Override
        protected Integer initialValue() {
            return 200;
        }
    }

然后,如果某个线程在执行过程中调用了treadLocal.get()方法,那么该线程就从自己那一亩地中取到属于它自己的值。

同理,如果某个线程在执行过程中调用了threadLocal.set(XXX)方法,那么该线程就把自己那一亩地的那个值修改成XXX。

我们看个完整的代码,来总结今天的所有内容。

public class ThreadLocalTest {

   private static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>(){
        @Override
        protected Integer initialValue() {
            return 200;
        }
    };

    //main主线程
    public static void main(String[] args) {
        //threadLocal.get()获取的是main主线程的值,是200
        System.out.println(Thread.currentThread().getName() + "-->" + threadLocal.get());
        //threadLocal.set(99)修改的是main主线程中的值,修改为99了
        threadLocal.set(99);
        System.out.println(Thread.currentThread().getName() + "--->" + threadLocal.get());

        new Thread(new MyRun()).start(); //thread-01
        new Thread(new MyRun()).start(); //thread-02
    }

    public static class MyRun implements Runnable{

        @Override
        public void run() {
          //若此时是thread-01线程在执行,则修改的是thread-01线程里的值
          //若此时是thread-02线程在执行,则修改的是thread-02线程里的值
            threadLocal.set((int)(Math.random()*100));
            //若此时是thread-01线程在执行,则得到的是thread-01线程里的值
          //若此时是thread-02线程在执行,则得到的是thread-02线程里的值
            System.out.println(Thread.currentThread().getName() + "--->" + threadLocal.get());
        }
    }
}

本文主要讲述了ThreadLocal的主要原理和使用方法,如果你们感兴趣的话可以去看看ThreadLocal的实现源码,相信你们会更加地明白编程的艺术!

【完】

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-08-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 IT界的泥石流 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档