谈谈 Java 面试中经常问到的ThreadLocal。

对于面试中经常问到的ThreadLocal很多同学并不是很了解,自然也不能很好地运用,今天我们就通过下面四个问题一起来了解一下吧~

多线程访问同一个共享变量的时候容易出现并发问题,特别是多个线程对一个变量进行写入的时候,为了保证线程安全,一般使用者在访问共享变量的时候需要进行额外的同步措施才能保证线程安全性。ThreadLocal是除了加锁这种同步方式之外的一种保证一种规避多线程访问出现线程不安全的方法,当我们在创建一个变量后,如果每个线程对其进行访问的时候访问的都是线程自己的变量这样就不会存在线程不安全问题。

Q: ThreadLocal的常见使用场景?

A:每个线程中需要维护1个不同的副本, 但这个副本可能是某一个时刻一起塞入每个线程的, 只不过之后该副本的变化 不再受其他线程的影响。

常见场景有连接器管理模块connectorManager, 每个线程持有的connect变量是单独使用的,不会互相影响或者需要加锁。原因就是将其作为副本放入每个线程,当线程启动连接或者关闭时,不影响其他线程里的getConnect方法。

Q: ThreadLocal和Synchronized关键字的区别?
A:

Synchronized是用时间的消耗,来换取数据同步以及互不冲突

ThreadLocal则是用空间的消耗,来换取数据之间互不冲突(不涉及同步)

Q:TheadLocal在每个线程中是以什么形式存储的? 原理是什么

A:这篇文章讲解ThreadLocal源码讲解的蛮好的:

Java并发编程:深入剖析

看完后用我自己的话总结一下就是:

  1. 在某个线程中调用 某threadlocal.set(value)时, 其实就是在该线程中新建了1个threalocalMap, 然后把threadLocal作为键,value作为值,放进本线程的threalocalMap中。
  2. 当在线程中调用threadlocal.get()的时候,就是从线程的threadLocalMap中获取这个threadLocal对应的值
    如果get不到,则可以通过自定义initValue方法生成一个threadLocal的默认值

见如下图所示:

Q: 下面这个代码会报什么错?(例子改编自上面链接的文章)

public class Test {
    ThreadLocal<String> stringLocal = new ThreadLocal<String>();
 
    public static void main(String[] args) throws InterruptedException {
        final Test test = new Test();
 
        System.out.println(test.getString());
 
        Thread thread1 = new Thread(){
            public void run() {
                System.out.println(stringLocal.get());
            };
        };
        thread1.start();
        thread1.join();
		stringLocal.set("thread0")
        System.out.println(test.getString());
    }
}

在Thread1中,会报空指针, 因为调用get之前没有做过set, 此时做get会报错。

一种方式改成这样:

展开阅读全文

本文系作者在时代Java发表,未经许可,不得转载。

如有侵权,请联系nowjava@qq.com删除。

编辑于

关注时代Java

关注时代Java