# 《并发设计模式》第42章-线程特有存储模式-到底什么是线程特有存储

作者:冰河
星球:http://m6z.cn/6aeFbs (opens new window)
博客:https://binghe.gitcode.host (opens new window)
文章汇总:https://binghe.gitcode.host/md/all/all.html (opens new window)
源码获取地址:https://t.zsxq.com/0dhvFs5oR (opens new window)

沉淀,成长,突破,帮助他人,成就自我。

  • 本章难度:★★☆☆☆
  • 本章重点:了解什么是线程特有存储模式,线程特有存储模式的应用场景,重点理解线程特有存储模式解决线程安全的核心思路与原理,能够融会贯通,并能够结合自身项目实际场景思考如何将线程特有存储模式灵活应用到自身实际项目中。

大家好,我是冰河~~

线程特有存储,顾名思义就是在线程内部存储一些数据,在线程内部存储数据话,一般就不会与其他线程共享,此时这些数据就是线程安全的,不会出现并发问题。这种将数据存储到线程本地的方式,在并发编程领域,也是一种设计模式,叫做线程特有存储模式。

# 一、故事背景

上回说到:小菜独立完成了生产环境多个请求数据错乱的问题,圆满完成了任务。但是对小菜这种积极上进的人来说,只是解决了问题还不行,他要搞定背后的核心原理和知识点才行。于是,小菜又找到老王请教关于ThreadLocal的知识,从老王那得知了其实在并发设计模式中还有一种线程特有存储模式。在老王耐心的讲解下,小菜也知道了什么是线程特有存储模式。

# 二、多线程共享变量问题

在Java程序中,如果一个变量在多个线程之间是共享的,就可能出现线程安全问题,如图42-1所示。


可以看到,当多个线程对内存中的同一个数据进行读取和修改操作时,每个线程都会在自己本地存储一份这个数据的副本,假设此时内存中的数据为0,线程A、线程B和线程C同时读取到了内存中的数据,都对数据进行加1操作。三个线程执行完的期望结果是3,但实际结果却是小于3。

主要的原因是线程A修改了内存中的数据,线程B和线程C是感知不到的。后续线程B和C向内存中写数据时,就会覆盖掉线程A的结果值。这就是共享变量所带来的线程安全问题。如果变量不在多个线程间共享,是不是就能避免线程安全问题呢?

# 三、局部变量线程安全

多个线程同时访问共享变量时,会导致并发问题。那么,如果将变量放在方法内部,是不是还会存在并发问题呢?如果不存在并发问题,那么为什么不会存在并发问题呢?

# 3.1 著名的斐波那契数列

记得上学的时候,我们都会遇到这样一种题目,打印斐波那契数列。斐波那契数列是这样的一个数列:1、1、2、3、5、8、13、21、34...,也就是说第1项和第2项是1,从第3项开始,每一项都等于前2项之和。我们可以使用下面的代码来生成斐波那契数列。

//生成斐波那契数列
public int[] fibonacci(int n){
    //存放结果的数组
    int[] result = new int[n];
    //数组的第1项和第2项为1
    result[0] = result[1] = 1;
    //计算第3项到第n项
    for(int i = 2; i < n; i++){
        result[i] = result[i-2] + result[i-1];
    }
    return result;
}
1
2
3
4
5
6
7
8
9
10
11
12

假设此时有很多个线程同时调用fibonacci()方法来生成斐波那契数列,对于方法中的局部变量result,会不会存在线程安全的问题呢?答案是:不会!!

接下来,我们就深入分析下为什么局部变量不会存在线程安全的问题!

# 查看全文

加入冰河技术 (opens new window)知识星球,解锁完整技术文章与完整代码