共计 1729 个字符,预计需要花费 5 分钟才能阅读完成。
摘要:ThreadLocal 是除了加锁同步形式之外的一种保障躲避多线程拜访呈现线程不平安的办法。
本文分享自华为云社区《4 问搞定 java 中的 ThreadLocal》,作者:breakDraw。
多线程拜访同一个共享变量的时候容易呈现并发问题,特地是多个线程对一个变量进行写入的时候,为了保障线程平安,个别使用者在访问共享变量的时候须要进行额定的同步措施能力保障线程安全性。ThreadLocal 是除了加锁这种同步形式之外的一种保障一种躲避多线程拜访呈现线程不平安的办法,当咱们在创立一个变量后,如果每个线程对其进行拜访的时候拜访的都是线程本人的变量这样就不会存在线程不平安问题。
Q:ThreadLocal 的常见应用场景?
A:每个线程中须要保护 1 个不同的正本,但这个正本可能是某一个时刻一起塞入每个线程的,只不过之后该正本的变动 不再受其余线程的影响。
常见场景有连接器治理模块 connectorManager,每个线程持有的 connect 变量是独自应用的,不会相互影响或者须要加锁。起因就是将其作为正本放入每个线程,当线程启动连贯或者敞开时,不影响其余线程里的 getConnect 办法。
Q:ThreadLocal 和 Synchronized 关键字的区别?
A:
Synchronized 是用工夫的耗费,来换取数据同步以及互不抵触
ThreadLocal 则是用空间的耗费,来换取数据之间互不抵触(不波及同步)
Q:TheadLocal 在每个线程中是以什么模式存储的?原理是什么
A:这篇文章解说 ThreadLocal 源码解说的蛮好的:
Java 并发编程:深刻分析
看完后用我本人的话总结一下就是:
- 在某个线程中调用 某 threadlocal.set(value)时,其实就是在该线程中新建了 1 个 threalocalMap,而后把 threadLocal 作为键,value 作为值,放进本线程的 threalocalMap 中。
- 当在线程中调用 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 会报错。
一种形式改成这样:
Thread thread1 = new Thread(){public void run() {stringLocal.set("thread1")
System.out.println(stringLocal.get());
};
};
另一种是给 stringLocal 设置默认值,这种个别用于能间接依据线程推导出初始值的状况:
ThreadLocal<String> stringLocal = new ThreadLocal<String>(){;
protected String initialValue() {return xxx;};
};
正确 set 之后,答案就会返回 thread0 和 thread1,且后续怎么 set,两边都不会相互影响各自的 threadLocal,尽管看起来是都用的是同一个 Test 里的成员。
点击关注,第一工夫理解华为云陈腐技术~