吗?
答:能。
一个典型的例子是在类中有一个 long 类型的成员变量。如果你知道该成员变量会被多个线
程访问,如计数器、价格等,你最好是将其设置为 volatile。为什么?因为 Java 中读取 long
类型变量不是原子的,需要分成两步,如果一个线程正在修改该 long 变量的值,另一个线
程可能只能看到该值的一半(前 32 位)。但是对一个 volatile 型的 long 或 double 变
量的读写是原子。
面试官:volatile 修饰符的有过什么实践?
一种实践是用 volatile 修饰 long 和 double 变量,使其能按原子类型来读写。double 和
long 都是 64 位宽,因此对这两种类型的读是分为两部分的,第一次读取第一个 32 位,然
后再读剩下的 32 位,这个过程不是原子的,但 Java 中 volatile 型的 long 或 double 变量
的读写是原子的。
volatile 修复符的另一个作用是提供内存屏障(memory barrier),例如在分布式框架中的
应用。简单的说,就是当你写一个 volatile 变量之前,Java 内存模型会插入一个写屏障
(write barrier),读一个 volatile 变量之前,会插入一个读屏障(read barrier)。意
思就是说,在你写一个 volatile 域时,能保证任何线程都能看到你写的值,同时,在写之
前,也能保证任何数值的更新对所有线程是可见的,因为内存屏障会将其他所有写的值更新
到缓存。
5、ThreadLocal(线程局部变量)关键
字?
答:当使用 ThreadLocal 维护变量时,其为每个使用该变量的线程提供独立的变量副本,所
以每一个线程都可以独立的改变自己的副本,而不会影响其他线程对应的副本。
ThreadLocal 内部实现机制:
每个线程内部都会维护一个类似 HashMap 的对象,称为 ThreadLocalMap,里边会包含若干
了 Entry(K-V 键值对),相应的线程被称为这些 Entry 的属主线程;
Entry 的 Key 是一个 ThreadLocal 实例,Value 是一个线程特有对象。Entry 的作用即是:
为其属主线程建立起一个 ThreadLocal 实例与一个线程特有对象之间的对应关系;
Entry 对 Key 的引用是弱引用;Entry 对 Value 的引用是强引用。
评论0