精通高并发与多线程,却不会用ThreadLocal?
作者:蔡不菜丶链接:来源:掘金
之前我们有在并发系列中提到 ThreadLocal 类和基本使用方法 , 那我们就来看下 ThreadLocal 究竟是如何使用的!
ThreadLocal 简介概念ThreadLocal 类是用来提供线程内部的局部变量 。 这种变量在多线程环境下访问(get 和 set 方法访问)时能保证各个线程的变量相对独立于其他线程内的变量 。ThreadLocal 实例通常来说都是 private static 类型的 , 用于关联线程和上下文 。
作用
- 传递数据
- 线程并发
- 线程隔离
ThreadLocal 实战1. 常见方法
- ThreadLocal ()
- void set (T value)
- T get ()
- void remove ()
2. 为什么要使用 ThreadLocal首先我们先看一组并发条件下的代码场景:
@Datapublic class ThreadLocalTest {private String name;public static void main(String[] args) {ThreadLocalTest tmp = new ThreadLocalTest();for (int i = 0; i < 4; i++) {Thread thread = new Thread(() -> {tmp.setName(Thread.currentThread().getName());System.out.println(Thread.currentThread().getName() +"\t 拿到数据:" + tmp.getName());});thread.setName("Thread-" + i);thread.start();}}}复制代码
我们理想中的代码输出结果应该是这样的:/** OUTPUT **/Thread-0拿到数据:Thread-0Thread-1拿到数据:Thread-1Thread-2拿到数据:Thread-2Thread-3拿到数据:Thread-3复制代码
但是实际上输出的结果却是这样的:/** OUTPUT **/Thread-0拿到数据:Thread-1Thread-3拿到数据:Thread-3Thread-1拿到数据:Thread-1Thread-2拿到数据:Thread-2复制代码
顺序乱了没有关系 , 但是我们可以看到 Thread-0 这个线程拿到的值却是 Thread-1从结果中我们可以看出多个线程在访问同一个变量的时候会出现异常 , 这是因为线程间的数据没有隔离!
并发线程出现的问题?那加锁不就完事了!这个时候你三下五除二的写下了以下代码:
@Datapublic class ThreadLocalTest {private String name;public static void main(String[] args) {ThreadLocalTest tmp = new ThreadLocalTest();for (int i = 0; i < 4; i++) {Thread thread = new Thread(() -> {synchronized (tmp) {tmp.setName(Thread.currentThread().getName());System.out.println(Thread.currentThread().getName()+ "\t" + tmp.getName());}});thread.setName("Thread-" + i);thread.start();}}}/** OUTPUT **/Thread-2 Thread-2Thread-3 Thread-3Thread-1 Thread-1Thread-0 Thread-0复制代码
从结果上看 , 加锁好像是解决了上述问题 , 但是 synchronized 常用于多线程数据共享的问题 , 而非多线程数据隔离的问题 。 这里使用 synchronized 虽然解决了问题 , 但是多少有些不合适 , 并且 synchronized 属于重量级锁 , 为了实现多线程数据隔离贸然的加上 synchronized , 也会影响到性能 。加锁的方法也被否定了 , 那么该如何解决?不如用 ThreadLocal 牛刀小试一番:
public class ThreadLocalTest {private static ThreadLocal threadLocal = new ThreadLocal<>();public String getName() {return threadLocal.get();}public void setName(String name) {threadLocal.set(name);}public static void main(String[] args) {ThreadLocalTest tmp = new ThreadLocalTest();for (int i = 0; i < 4; i++) {Thread thread = new Thread(() -> {tmp.setName(Thread.currentThread().getName());System.out.println(Thread.currentThread().getName() +"\t 拿到数据:" + tmp.getName());});thread.setName("Thread-" + i);thread.start();}}}复制代码
在查看输出结果之前 , 我们先来看看代码发生了哪些变化【精通高并发与多线程,却不会用ThreadLocal?】首先多了一个 private static 修饰的 ThreadLocal, 然后在 setName 的时候 , 我们实际上是往 ThreadLocal 里面存数据 , 在 getName 的时候 , 我们是在 ThreadLocal 里面取数据 。 感觉操作上也是挺简单的 , 但是这样真的能做到线程间的数据隔离吗 , 我们再来看一看结果:
/** OUTPUT **/Thread-1拿到数据:Thread-1Thread-2拿到数据:Thread-2Thread-0拿到数据:Thread-0Thread-3拿到数据:Thread-3复制代码
从结果上可以看到每个线程都能取到对应的数据 。 ThreadLocal 也已经解决了多线程之间数据隔离的问题 。那么我们来小结一下 , 为什么需要使用ThreadLocal , 与 synchronized 的区别是什么
- synchronized
- 精英|业务流程图怎么绘制?销售精英的经验之谈
- 广东移动OTN精智专网,助力千行百业数字化转型
- 关闭|虾米音乐的关闭,再次应证了互联网下竞争的规则,小而精很难生存
- 巨人|全国专精特新“小巨人”企业出炉!湖北三峰透平江南专汽入选!
- 手机|年底换机?iQOO 5系列配OriginOS系统将会相当精彩
- Store|苹果将在韩国开设第二家Apple Store直营店 并发布纪念壁
- Pro|Redmi Note 9 5G/Pro正式开售!1299元起每款都精彩
- 黔东南州|黔东南州驻长沙招商分队与猪八戒科技服务有限公司精准对接实施项目
- 5G体温精准筛查大数据系统解决方案(ppt)
- Linux(服务器编程):百万并发服务器系统参数调优