目录
- 1. 说明
- 2. 如何避免Java伪共享
- 2.1 手动填充缓存行
- 2.2 使用JDK8的@Contended注解
- 2.3 使用volatile关键字
1. 说明
- 1.伪共享是多线程编程中的一个性能问题,具体指在多线程环境中,不同线程更新同一缓存行中的不同变量时,由于缓存行的粒度,这些线程可能会频繁地读写同一缓存行,进而产生缓存冲突,导致程序性能下降。
- 2.如果多个线程同时访问并更新位于同一个缓存行中的不同变量,就会触发缓存锁定,使得整个缓存行的内容都被锁定,其他需要访问该缓存行中任意变量的线程都将被迫等待。
2. 如何避免Java伪共享
2.1 手动填充缓存行
- 1.由于CPU缓存行的大小一般为64字节或128字节,因此可以通过在变量之间插入足够数量的其他变量(如long类型),来占满一个缓存行,从而确保目标变量位于独立的缓存行中。
- 2.例如,在需要避免伪共享的变量前后分别添加多个long类型的变量作为填充,这样目标变量就会被分配到独立的缓存行中,避免了与其他变量的缓存冲突。
2.2 使用JDK8的@Contended注解
- 1.在JDK8及之后的版本中,可以使用@Contended注解来避免伪共享问题。
- 2.这个注解只能用于类和属性,并需要手动启用JVM的-XX:-RestrictContended参数才能生效。
- 3.使用@Contended注解后,编译器会自动进行内存填充,使得被注解的字段与其他字段占据不同的缓存行,从而避免伪共享。
- 4.使用@Contended注解可能会改变内存布局,带来一些不可预期的行为,因此在使用时需要特别小心,并进行充分的测试和评估。
2.3 使用volatile关键字
- 1.volatile关键字在Java中具有可见性和有序性的特性,这些特性有助于避免假共享问题。
- 2.当一个线程修改了一个volatile变量的值时,其他线程可以立即看到这个修改,这保证了不同线程对volatile变量的读写操作都是可见的。
- 3.volatile关键字可以禁止指令重排序,确保多线程程序的正确执行顺序。
- 4.通过将需要避免伪共享的变量声明为volatile变量,可以减少线程之间的缓存冲突,从而避免伪共享问题。但需要注意的是,volatile关键字并不能保证原子性,如果需要保证原子性,还需要使用其他同步机制。