ThreadLocal学习笔记

并发编程

并发编程的时候,成员变量如果不做任何处理其实是线程不安全的,各个线程都在操作同一个变量,显然是不行的,并且我们也知道volatile这个关键字也是不能保证线程安全的。那么在有一种情况之下,我们需要满足这样一个条件:变量是同一个,但是每个线程都使用同一个初始值,也就是使用同一个变量的一个新的副本。这种情况之下ThreadLocal就非常使用,比如说DAO的数据库连接,我们知道DAO是单例的,那么他的属性Connection就不是一个线程安全的变量。而我们每个线程都需要使用他,并且各自使用各自的。这种情况,ThreadLocal就比较好的解决了这个问题。

1. volatile

参考链接

volatile关键字保证线程操作的可见性;

  1. 保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的;
  2. 禁止进行指令重排序;
  3. 使用volatile关键字会强制将修改的值立即写入主存;
  4. 使用volatile关键字的话,当线程A进行修改时,会导致线程B的工作内存中缓存变量,如stop的缓存行无效(反映到硬件层的话,就是CPU的L1或者L2缓存中对应的缓存行无效);
  5. 由于线程A的工作内存中缓存变量stop的缓存行无效,所以线程A再次读取变量stop的值时会去主存读取;
  6. 在线程B修改stop值时(当然这里包括2个操作,修改线程B工作内存中的值,然后将修改后的值写入内存),会使得线程A的工作内存中缓存变量stop的缓存行无效,然后线程A读取时,发现自己的缓存行无效,它会等待缓存行对应的主存地址被更新之后,然后去对应的主存读取最新的值。那么线程A读取到的就是最新的正确的值。

volatile关键字无法保证线程操作的原子性

对于非原子性操作,如自增操作,对变量a = 10进行自加1操作,当线程A读入变量后被阻塞,因为还未修改,线程B读入a = 10,自加1将a = 11写入主存,线程A继续执行时,由于已经读取了变量a,不会再去主存读取,因此同样写入a = 11进主存,这中间,a一共做了两次自加1操作,但结果只有11。

volatile无法完全保证指令有序性

在前面提到volatile关键字能禁止指令重排序,所以volatile能在一定程度上保证有序性。
volatile关键字禁止指令重排序有两层意思:

  1. 对后面的操作可见;在其后面的操作肯定还没有进行;
  2. 在进行指令优化时,不能将在对volatile变量访问的语句放在其后面执行,也不能把volatile变量后面的语句放到其前面执行。

使用volatile的条件

  1. 对变量的写操作不依赖于当前值
  2. 该变量没有包含在具有其他变量的不变式中

2. DAO模式

参考链接

一个为数据库或其他持久化机制提供了抽象接口的对象,在不暴露底层持久化方案实现细节的前提下提供了各种数据访问操作。用程序设计语言来说,就是建立一个接口,接口中定义了此应用程序中将会用到的所有事务方法。在这个应用程序中,当需要和数据源进行交互的时候则使用这个接口,并且编写一个单独的类来实现这个接口,在逻辑上该类对应一个特定的数据存储。

DAO模式组成:

  1. DAO接口:把对数据库的所有操作定义成抽象方法,可以提供多种实现;
  2. DAO实现类:针对不同数据库给出DAO接口定义方法的具体实现;
  3. 实体类:用于存放于传输对象数据;
  4. 数据库连接和关闭工具类:避免数据库连接和关闭代码的重复使用,方便修改;

3. ThreadLocal

参考链接

ThreadLocal用于创建线程局部变量。通常情况下,我们创建的变量是可以被任何一个线程访问并修改的,而使用ThreadLocal创建的变量只能被当前线程访问,其他线程则无法访问和修改。
ThreadLocal,连接ThreadLocalMap和Thread。来处理Thread的TheadLocalMap属性,包括init初始化属性赋值、get对应的变量,set设置变量等。通过当前线程,获取线程上的ThreadLocalMap属性,对数据进行get、set等操作。ThreadLocalMap,用来存储数据,采用类似hashmap机制,存储了以threadLocal为key,需要隔离的数据为value的Entry键值对数组结构。

ThreadLocal使用场景

  1. 实现单个线程单例以及单个线程上下文信息存储,比如交易id等;
  2. 实现线程安全,非线程安全的对象使用ThreadLocal之后就会变得线程安全,因为每个线程都会有一个对应的实例;
  3. 承载一些线程相关的数据,避免在方法中来回传递参数;
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 第6章类文件结构 6.1 概述 6.2 无关性基石 6.3 Class类文件的结构 java虚拟机不和包括java...
    kennethan阅读 967评论 0 2
  • 九种基本数据类型的大小,以及他们的封装类。(1)九种基本数据类型和封装类 (2)自动装箱和自动拆箱 什么是自动装箱...
    关玮琳linSir阅读 1,913评论 0 47
  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,136评论 1 32
  • Java SE 基础: 封装、继承、多态 封装: 概念:就是把对象的属性和操作(或服务)结合为一个独立的整体,并尽...
    Jayden_Cao阅读 2,134评论 0 8
  • 线程池ThreadPoolExecutor corepoolsize:核心池的大小,默认情况下,在创建了线程池之后...
    irckwk1阅读 756评论 0 0