多线程并发中的ThreadLocal和volatile

并发编程有三个基本概念:
(1)原子性
即一个操作或者多个操作 要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行。
java中原子性操作包括以下几类:

   1. 基本类型的读取和赋值操作,且赋值必须是数字赋值给变量,变量之间的相互赋值不是原子性操作
   2. 所有引用reference的赋值操作
   3. java.concurrent.Atomic.* 包中所有类的一切操作

(2)可见性
指当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值。
在多线程环境下,一个线程对共享变量的操作对其他线程是不可见的。Java提供了volatile来保证可见性,当一个变量被volatile修饰后,表示着线程本地内存无效,当一个线程修改共享变量后他会立即被更新到主内存中,其他线程读取共享变量时,会直接从主内存中读取。当然,synchronizeLock都可以保证可见性。synchronizedLock能保证同一时刻只有一个线程获取锁然后执行同步代码,并且在释放锁之前会将对变量的修改刷新到主存当中。因此可以保证可见性。

(3)有序性
即程序执行的顺序按照代码的先后顺序执行。
在Java内存模型中,为了效率是允许编译器和处理器对指令进行重排序,当然重排序不会影响单线程的运行结果,但是对多线程会有影响。Java提供volatile来保证一定的有序性。最著名的例子就是单例模式里面的DCL(双重检查锁)。另外,可以通过synchronizedLock来保证有序性,synchronizedLock保证每个时刻是有一个线程执行同步代码,相当于是让线程顺序执行同步代码,自然就保证了有序性。

ThreadLocal

ThreadLocal是线程局部变量,是线程内独享的,在进程中定义的一个变量需要在每个线程内部独自操作,互相隔离。

实现原理:
线程Thread内部有个ThreadLocalMap变量,首先根据当前线程对象get到该线程的threadLocalMap,这个map中定义了Entry,用于存储每个threadLocal对象与对应的泛型T的值(或对象)。
Thread ——> ThreadLocalMap ——> {ThreadLocal对象 -> T}
一个线程拥有一个ThreadLocalMap,但一个ThreadLocalMap中可以存多个线程的局部变量。

ThreadLocal的应用场景:
(1)在一个多线程中,每个线程独享变量
(2)参数传递,有点spark中广播变量的意思

Volatile

Volatile是修饰符关键字,用来修饰变量(该变量是线程共享变量),一旦一个变量被volatile修饰意味着三点:
(1)一个线程对于该变量的修改,对于其他线程都是可见的,即所有线程对于该变量的读操作都是直接从主存中读取,而线程对变量的修改也是强制刷新到主存中的;
(2)禁止编译器的重排序,对于该变量的操作前和操作后的代码不能变序。即当程序执行到volatile变量的读操作或者写操作时,在其前面的操作的更改肯定全部已经进行,且结果已经对后面的操作可见;在其后面的操作肯定还没有进行。
(3)Volatile只保证变量的可见性,不保证针对该变量操作的原子性。

你可能感兴趣的:(多线程并发中的ThreadLocal和volatile)