多线程(72)False Sharing

2024-04-25 13:04
文章标签 多线程 false 72 sharing

本文主要是介绍多线程(72)False Sharing,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

False Sharing(伪共享)是并发编程中的一个性能问题,它发生在多个线程访问并修改相互独立的变量时,这些变量恰好位于同一个缓存行(Cache Line)内。现代CPU为了提高访问内存的速度,会将内存分成一系列的缓存行,通常大小为64字节,并且以缓存行为单位将数据从主存(RAM)加载到CPU缓存中。当一个线程修改了一个缓存行内的数据时,处于同一缓存行的其他数据也会被标记为无效,导致其他线程在访问自己的变量时不得不重新从主存中加载整个缓存行,即使它们只是想要读取自己的独立变量。

举个例子

考虑以下Java代码,其中模拟了两个线程并发更新两个独立变量的情况:

public class FalseSharingExample implements Runnable {public final static int NUM_THREADS = 2; // 线程数public final static long ITERATIONS = 500L * 1000L * 1000L;private final int arrayIndex;private static VolatileLong[] longs = new VolatileLong[NUM_THREADS];static {for (int i = 0; i < longs.length; i++) {longs[i] = new VolatileLong();}}public FalseSharingExample(final int arrayIndex) {this.arrayIndex = arrayIndex;}public static void main(final String[] args) throws Exception {final long start = System.nanoTime();runTest();System.out.println("Duration = " + (System.nanoTime() - start));}private static void runTest() throws InterruptedException {Thread[] threads = new Thread[NUM_THREADS];for (int i = 0; i < threads.length; i++) {threads[i] = new Thread(new FalseSharingExample(i));}for (Thread t : threads) {t.start();}for (Thread t : threads) {t.join();}}public void run() {long i = ITERATIONS + 1;while (0 != --i) {longs[arrayIndex].value = i;}}public final static class VolatileLong {public volatile long value = 0L;}
}

在这个例子中,有两个线程分别更新数组longs中的两个独立元素。由于VolatileLong对象很小,它们很可能被放置在同一个缓存行中。这意味着当一个线程更新它的value变量时,可能会导致另一个线程的缓存行无效,因此增加了不必要的内存访问延迟。

解决伪共享

解决伪共享的一种常见方法是通过增加填充(Padding)来强制每个被频繁写入的变量都位于不同的缓存行中。Java 8引入了@Contended注解,但默认是禁用的,您需要在JVM启动时通过-XX:-RestrictContended来启用它。下面是一个增加了填充以避免伪共享的示例:

public final static class PaddedVolatileLong {// 增加填充public volatile long p1, p2, p3, p4, p5, p6 = 7L;public volatile long value = 0L;// 对齐到另一个缓存行,避免伪共享public volatile long q1, q2, q3, q4, q5, q6 = 7L;
}

这种方法通过增加一些无用的变量p1p6q1q6,确保value前后有足够的空间将它与其他频繁写入的变量隔开,从而避免它们落在同一个缓存行中。

总结

伪共享是一个微妙但重要的性能问题,它可能导致并发程序的性能显著下降。通过合理的设计和一些高级特性(如Java的@Contended注解或者手动填充),可以减轻甚至避免伪共享带来的影响。理解并发程序中的缓存行为对于编写高效的多线程代码至关重要。

这篇关于多线程(72)False Sharing的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/934763

相关文章

Python多线程实现大文件快速下载的代码实现

《Python多线程实现大文件快速下载的代码实现》在互联网时代,文件下载是日常操作之一,尤其是大文件,然而,网络条件不稳定或带宽有限时,下载速度会变得很慢,本文将介绍如何使用Python实现多线程下载... 目录引言一、多线程下载原理二、python实现多线程下载代码说明:三、实战案例四、注意事项五、总结引

Python多线程应用中的卡死问题优化方案指南

《Python多线程应用中的卡死问题优化方案指南》在利用Python语言开发某查询软件时,遇到了点击搜索按钮后软件卡死的问题,本文将简单分析一下出现的原因以及对应的优化方案,希望对大家有所帮助... 目录问题描述优化方案1. 网络请求优化2. 多线程架构优化3. 全局异常处理4. 配置管理优化优化效果1.

Qt中实现多线程导出数据功能的四种方式小结

《Qt中实现多线程导出数据功能的四种方式小结》在以往的项目开发中,在很多地方用到了多线程,本文将记录下在Qt开发中用到的多线程技术实现方法,以导出指定范围的数字到txt文件为例,展示多线程不同的实现方... 目录前言导出文件的示例工具类QThreadQObject的moveToThread方法实现多线程QC

RabbitMQ消费端单线程与多线程案例讲解

《RabbitMQ消费端单线程与多线程案例讲解》文章解析RabbitMQ消费端单线程与多线程处理机制,说明concurrency控制消费者数量,max-concurrency控制最大线程数,prefe... 目录 一、基础概念详细解释:举个例子:✅ 单消费者 + 单线程消费❌ 单消费者 + 多线程消费❌ 多

Javaee多线程之进程和线程之间的区别和联系(最新整理)

《Javaee多线程之进程和线程之间的区别和联系(最新整理)》进程是资源分配单位,线程是调度执行单位,共享资源更高效,创建线程五种方式:继承Thread、Runnable接口、匿名类、lambda,r... 目录进程和线程进程线程进程和线程的区别创建线程的五种写法继承Thread,重写run实现Runnab

使用Python实现可恢复式多线程下载器

《使用Python实现可恢复式多线程下载器》在数字时代,大文件下载已成为日常操作,本文将手把手教你用Python打造专业级下载器,实现断点续传,多线程加速,速度限制等功能,感兴趣的小伙伴可以了解下... 目录一、智能续传:从崩溃边缘抢救进度二、多线程加速:榨干网络带宽三、速度控制:做网络的好邻居四、终端交互

python多线程并发测试过程

《python多线程并发测试过程》:本文主要介绍python多线程并发测试过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、并发与并行?二、同步与异步的概念?三、线程与进程的区别?需求1:多线程执行不同任务需求2:多线程执行相同任务总结一、并发与并行?1、

Python多进程、多线程、协程典型示例解析(最新推荐)

《Python多进程、多线程、协程典型示例解析(最新推荐)》:本文主要介绍Python多进程、多线程、协程典型示例解析(最新推荐),本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定... 目录一、multiprocessing(多进程)1. 模块简介2. 案例详解:并行计算平方和3. 实现逻

Java使用多线程处理未知任务数的方案介绍

《Java使用多线程处理未知任务数的方案介绍》这篇文章主要为大家详细介绍了Java如何使用多线程实现处理未知任务数,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 知道任务个数,你可以定义好线程数规则,生成线程数去跑代码说明:1.虚拟线程池:使用 Executors.newVir

JAVA封装多线程实现的方式及原理

《JAVA封装多线程实现的方式及原理》:本文主要介绍Java中封装多线程的原理和常见方式,通过封装可以简化多线程的使用,提高安全性,并增强代码的可维护性和可扩展性,需要的朋友可以参考下... 目录前言一、封装的目标二、常见的封装方式及原理总结前言在 Java 中,封装多线程的原理主要围绕着将多线程相关的操