Java并发编程实战
王宝令
资深架构师
立即订阅
15151 人已学习
课程目录
已完结 50 讲
0/4登录后,你可以任选4讲全文学习。
开篇词 (1讲)
开篇词 | 你为什么需要学习并发编程?
免费
学习攻略 (1讲)
学习攻略 | 如何才能学好并发编程?
第一部分:并发理论基础 (13讲)
01 | 可见性、原子性和有序性问题:并发编程Bug的源头
02 | Java内存模型:看Java如何解决可见性和有序性问题
03 | 互斥锁(上):解决原子性问题
04 | 互斥锁(下):如何用一把锁保护多个资源?
05 | 一不小心就死锁了,怎么办?
06 | 用“等待-通知”机制优化循环等待
07 | 安全性、活跃性以及性能问题
08 | 管程:并发编程的万能钥匙
09 | Java线程(上):Java线程的生命周期
10 | Java线程(中):创建多少线程才是合适的?
11 | Java线程(下):为什么局部变量是线程安全的?
12 | 如何用面向对象思想写好并发程序?
13 | 理论基础模块热点问题答疑
第二部分:并发工具类 (14讲)
14 | Lock和Condition(上):隐藏在并发包中的管程
15 | Lock和Condition(下):Dubbo如何用管程实现异步转同步?
16 | Semaphore:如何快速实现一个限流器?
17 | ReadWriteLock:如何快速实现一个完备的缓存?
18 | StampedLock:有没有比读写锁更快的锁?
19 | CountDownLatch和CyclicBarrier:如何让多线程步调一致?
20 | 并发容器:都有哪些“坑”需要我们填?
21 | 原子类:无锁工具类的典范
22 | Executor与线程池:如何创建正确的线程池?
23 | Future:如何用多线程实现最优的“烧水泡茶”程序?
24 | CompletableFuture:异步编程没那么难
25 | CompletionService:如何批量执行异步任务?
26 | Fork/Join:单机版的MapReduce
27 | 并发工具类模块热点问题答疑
第三部分:并发设计模式 (10讲)
28 | Immutability模式:如何利用不变性解决并发问题?
29 | Copy-on-Write模式:不是延时策略的COW
30 | 线程本地存储模式:没有共享,就没有伤害
31 | Guarded Suspension模式:等待唤醒机制的规范实现
32 | Balking模式:再谈线程安全的单例模式
33 | Thread-Per-Message模式:最简单实用的分工方法
34 | Worker Thread模式:如何避免重复创建线程?
35 | 两阶段终止模式:如何优雅地终止线程?
36 | 生产者-消费者模式:用流水线思想提高效率
37 | 设计模式模块热点问题答疑
第四部分:案例分析 (4讲)
38 | 案例分析(一):高性能限流器Guava RateLimiter
39 | 案例分析(二):高性能网络应用框架Netty
40 | 案例分析(三):高性能队列Disruptor
41 | 案例分析(四):高性能数据库连接池HiKariCP
第五部分:其他并发模型 (4讲)
42 | Actor模型:面向对象原生的并发模型
43 | 软件事务内存:借鉴数据库的并发经验
44 | 协程:更轻量级的线程
45 | CSP模型:Golang的主力队员
结束语 (1讲)
结束语 | 十年之后,初心依旧
用户故事 (2讲)
用户来信 | 真好,面试考到这些并发编程,我都答对了!
3 个用户来信 | 打开一个新的并发世界
Java并发编程实战
登录|注册

30 | 线程本地存储模式:没有共享,就没有伤害

王宝令 2019-05-07
民国年间某山东省主席参加某大学校庆演讲,在篮球场看到十来个人穿着裤衩抢一个球,观之实在不雅,于是怒斥学校的总务处长贪污,并且发话:“多买几个球,一人发一个,省得你争我抢!”小时候听到这个段子只是觉得好玩,今天再来看,却别有一番滋味。为什么呢?因为其间蕴藏着解决并发问题的一个重要方法:避免共享
我们曾经一遍一遍又一遍地重复,多个线程同时读写同一共享变量存在并发问题。前面两篇文章我们突破的是写,没有写操作自然没有并发问题了。其实还可以突破共享变量,没有共享变量也不会有并发问题,正所谓是没有共享,就没有伤害
那如何避免共享呢?思路其实很简单,多个人争一个球总容易出矛盾,那就每个人发一个球。对应到并发编程领域,就是每个线程都拥有自己的变量,彼此之间不共享,也就没有并发问题了。
我们在《11 | Java 线程(下):为什么局部变量是线程安全的?》中提到过线程封闭,其本质上就是避免共享。你已经知道通过局部变量可以做到避免共享,那还有没有其他方法可以做到呢?有的,Java 语言提供的线程本地存储(ThreadLocal)就能够做到。下面我们先看看 ThreadLocal 到底该如何使用。

ThreadLocal 的使用方法

取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《Java并发编程实战》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(39)

  • 右耳听海
    有个疑问请教老师,避免共享变量的两种解决方案,在高并发情况下,使用局部变量会频繁创建对象,使用threadlocal也是针对线程创建新变量,都是针对线程维度,threadlocal并未体现出什么优势,为什么还要用threadlocal

    作者回复: threadlocal=线程数,局部变量=调用量,差距太大了

    2019-05-07
    1
    33
  • 晓杰
    不可以,因为ThreadLocal内的变量是线程级别的,而异步编程意味着线程不同,不同线程的变量不可以共享

    作者回复: 👍

    2019-05-07
    22
  • QQ怪
    上面有些同学说多线程是simpledateformat会打印出一样名称的对象,我刚刚也试了下,的确可以复现,但其实是simpledateformat对象的toString()方法搞得鬼,该类是继承object类的tostring方法,如下有个hashcode()方法,但该类重写了hashcode方法,在追溯到hashcode方法,pattern.hashcode(),pattern就是我们的yyyy-MM-dd,这个是一直保持不变的,现在终于真相大白了

    作者回复: 感谢回复!!!!

    2019-05-07
    16
  • linqw
    自己写了下对ThreadLocal的源码分析https://juejin.im/post/5ce7e0596fb9a07ee742ba79,感兴趣的可以看下哦,老师也帮忙看下哦

    作者回复: 有心👍

    2019-05-25
    5
  • 承香墨影
    老师您好,有个问题想请教。
    在线程池中使用 ThreadLocal,您给的解决方案是,使用后手动释放。
    那这样和使用线程的局部变量有什么区别?每次线程执行的时候都去创建对象并存储在 ThreadLocal 中,用完就释放掉了,下次执行依然需要重新创建,并存入 ThreadLocalMap 中,这样并没有解决局部变量频繁创建对象的问题。

    作者回复: 这种用法一般是为了在一个线程里传递全局参数,也叫上下文信息,局部变量不能跨方法,这个用法不是用来解决局部变量重复创建的

    2019-05-22
    4
  • java实现异步的方式基本上就是多线程了,而threadlocal是线程封闭的,不能在线程之间共享,就谈不上全局的事务管理了。
    2019-05-07
    4
  • GEEKBANG_6638780
    @vic
    想问一下如果gc发生在对threadLocal的 set和get操作之间,get的时候value对应的key已经被gc了,不是拿不到我之前放进threadLocal的对象了吗?这样对业务不会有问题吗?
    ---------------------------------
    是的,一般建议threadlocal采用static修饰,而且遵循try finally编程
    2019-06-12
    3
  • 晓杰
    请问一下老师,我刚刚对simpledateformat加threadlocal,但是不同线程得到的simpledateformat对象是一样的,代码如下:
    public class Tool {
        public static void main(String[] args) throws Exception{
            System.out.println(SafeDateFormat.get());
            System.out.println(Thread.currentThread().getName());
            new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName());
                    System.out.println(SafeDateFormat.get());
                }
            }).start();

        }

        static class SafeDateFormat{
            static final ThreadLocal<SimpleDateFormat> sdf =
                    ThreadLocal.withInitial(()->new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
            static SimpleDateFormat get(){
                return sdf.get();
            }
        }
    }
    请问存在什么问题

    作者回复: 有同学已经找到原因了,是tostring的锅

    2019-05-07
    3
  • ddup
    System.identityHashCode(dateFormat)); 这个来打印内存地址。
    2019-05-16
    2
  • 刘晓林
    getEntry(): 0x61c88647,解决hash碰撞的一个神奇的数
    2019-05-11
    2
  • vic
    想问一下如果gc发生在对threadLocal的 set和get操作之间,get的时候value对应的key已经被gc了,不是拿不到我之前放进threadLocal的对象了吗?这样对业务不会有问题吗?
    2019-05-07
    2
  • 张三
    打卡!我认为不行吧,文末提到ThreadLocal创建的线程变量子线程无法继承了。
    2019-05-07
    2
  • 盐多必失
    某山东省主席…… 宝令小哥哥这加密算法做得太好了,^_^

    作者回复: 大智若愚,谁说的清呢,一起鄙视那些不加密的吧😄

    2019-06-09
    1
  • 看不到de颜色
    异步编程应该慎用ThreadLocal。因为不再是同一个线程执行,所以获取不到原本想获取的数据
    2019-05-19
    1
  • QQ怪
    扩展:可以打断点进ThreadLocal的getmap方法里面可以直接看到slf对象是不同的
    2019-05-07
    1
  • 张三
    这节的ThreadLocal,我记得15年刚开始工作的时候,工作中有一个需要动态切换数据源的需求,Spring+Hibernate框架,当时通过百度查到用ThreadLocal,使用AOP在进入service层之前来切换数据源。正好跟这里文章说的Spring使用ThreadLocal来传递事物信息意思一样吧。
    2019-05-07
    1
  • 梦倚栏杆
    有个疑问:Thread 对象和运行的线程是同一个东西吗,如果不是,能解释一下区别吗?如果是有如下疑问:
    ThreadLocal 创建map时有如下代码。
    void createMap(Thread t, T firstValue) {
            t.threadLocals = new ThreadLocalMap(this, firstValue);
        }

    如果在一个执行流程里定义了多个theadLocal, 根据这段代码,t.threadLocals的引用就指向了最后一个threadLocal的定义。感觉java sdk 肯定不会这样啊。老师能解释一下吗?
    2019-12-11
  • B+Tree
    老师好,请教个问题。弱引用对象只能生存到下一次gc前,如果下一次gc时线程还在而且我还需要用到threadlocal,这时候岂不是取不到数据?
    2019-11-27
  • Demon.Lee
    老师,对于ThreadLocal导致内存泄漏,整体逻辑上我是明白的,但有一点还是糊涂,我也去google很多文章,还是不完全明白。就是这个Entry数组里面的弱引用,它会在下一次GC之后就被回收了,但这个回收仅仅只是ThreadLocal实例的一个引用吧,ThreadLocal实例对象自身是final static修饰的,它应该一直都在吧。这个ThreadLocal实例对象是所有线程都会引用的,也就是说,内存泄漏的主要还是value,跟这个key没什么太大关系。如果这个key又改回强引用,那么内存泄漏也只是多了一个ThreadLocal实例的引用,我的理解对么?
    2019-10-20
  • So
    一个ThreadLocal只能保存一个变量,那如果有多个变量要保存,是不是要建多个ThreadLocal?

    作者回复: 是的

    2019-09-11
收起评论
39
返回
顶部