性能优化之@Contended减少伪共享

简介: 说到伪共享,就要说CPU缓存,我们程序执行时候信息会被保存到CPU缓存中而这些缓存中的数据可能被多线程访问,假如一个线程还没处理完,另外一个线程就对数据进行了修改,就会导致上一个线程发生幻读的情况,比如刚才看到a=1,然后准备a = a+1。但是还没做,另外一个线程就先将a变成2了。导致了上一个线程计算后本来应该是a = 1 + 1,变成了a = 2 + 1计算结果就不对了。

一、什么叫伪共享

说到伪共享,就要说CPU缓存,我们程序执行时候信息会被保存到CPU缓存中
而这些缓存中的数据可能被多线程访问,假如一个线程还没处理完,另外一个线程
就对数据进行了修改,就会导致上一个线程发生幻读的情况,比如刚才看到a=1,然后准备a = a+1。
但是还没做,另外一个线程就先将a变成2了。导致了上一个线程计算后本来应该是a = 1 + 1,变成了a = 2 + 1
计算结果就不对了。

那么对于这种情况当然是不允许发生的,解决方案就是当发现另外一个线程更新了共享变量,就会把cpu缓存中的数据给失效。
然后都重新读取最新的变量值。

==这里有一个前提是共享变量,因为两个线程都会用到a,所以a是共享变量。==

那么我们在聊伪共享就简单了,下面举一个伪共享变量的例子。

public class ContendedTest {

    volatile long a;
    
    volatile long b;
    
    @Test
    public void test() throws Exception {
        ContendedTest c = new ContendedTest();
        Thread thread1 = new Thread(() -> {
            for (int i = 0; i < 10000_0000L; i++) {
                c.a = i;
            }
        });
        Thread thread2 = new Thread(() -> {
            for (int i = 0; i < 10000_0000L; i++) {
                c.b = i;
            }
        });
        final long start = System.nanoTime();
        thread1.start();
        thread2.start();
        thread1.join();
        thread2.join();
        // 1933
        System.out.println((System.nanoTime() - start) / 100_0000);
    }
     
}    

两个线程分别来更新a和b属性,根据缓存失效的原理,因为a和b都在同一个对象中,当一个属性被更新,就会触发cpu缓存失效。
那么等于这种情况cpu缓存就没什么用了。我们思考下两个线程分别更新a和b,而a和b没有任何关系。那么a和b是共享变量吗?
当然不是,这就叫伪共享。

二、主动告诉程序伪共享

我们可以使用 @Contended 来声明伪共享变量,从而是cpu不更新缓存。
本地测试时候记得加上jvm参数 ==-XX:-RestrictContended==,否则无效哦。

public class ContendedTest {

    @Contended
    volatile int a;

    @Contended
    volatile int b;

    @Test
    public void test() throws Exception {
        ContendedTest c = new ContendedTest();
        Thread thread1 = new Thread(() -> {
            for (int i = 0; i < 10000_0000L; i++) {
                c.a = i;
            }
        });
        Thread thread2 = new Thread(() -> {
            for (int i = 0; i < 10000_0000L; i++) {
                c.b = i;
            }
        });
        final long start = System.nanoTime();
        thread1.start();
        thread2.start();
        thread1.join();
        thread2.join();
        System.out.println((System.nanoTime() - start) / 100_0000);
    }
}

那么你猜下性能能提高多少呢? 前者1933后者758ms,差不多2.5倍的样子。

那么留下一个问题? 有多少场景都在使用@Contended呢? 知道的请留言评论。

相关文章
|
机器学习/深度学习 文字识别 算法
【OCR学习笔记】2、OCR图像预处理(上)
【OCR学习笔记】2、OCR图像预处理(上)
2300 0
|
小程序
微信小程序:计算属性和监听属性miniprogram-computed
微信小程序:计算属性和监听属性miniprogram-computed
1103 0
|
canal 存储 算法
跨系统实时同步数据解决方案
数据量太大,单存储节点存不下,就只能把数据分片存储。
1559 0
|
机器人
太空采矿:地球资源枯竭后的替代方案
【10月更文挑战第10天】太空采矿作为地球资源枯竭后的替代方案,具有广阔的前景和潜力。然而,要实现太空采矿的商业化和可持续发展,还需要克服一系列技术、经济和法律挑战。未来,随着技术的不断进步和国际合作的加强,太空采矿将成为人类社会新的资源来源和经济增长点。让我们共同期待太空采矿的美好未来!
|
机器学习/深度学习 安全 API
爱回收平台技术揭秘:构建高效、安全、用户友好的二手物品回收生态系统
爱回收利用微服务架构打造高效安全的二手电子回收平台。系统通过API Gateway处理前端请求,各微服务独立处理业务逻辑,如商品评估、订单创建和支付结算,采用机器学习算法预估价格。安全策略包括OAuth2.0授权、数据加密、访问控制和DDoS防护。性能优化涉及缓存、负载均衡及数据库优化,提供便捷、透明的服务,促进可持续发展。
818 1
|
算法 数据可视化 机器人
使用Python进行二维图像的三维重建
2D图像的三维重建是从一组2D图像中创建对象或场景的三维模型的过程。这个技术广泛应用于计算机视觉、机器人技术和虚拟现实等领域。 在本文中,我们将解释如何使用Python执行从2D图像到三维重建的过程。我们将使用TempleRing数据集作为示例,逐步演示这个过程。该数据集包含了在对象周围的一个环上采样的阿格里真托(Agrigento)“Dioskouroi神庙”复制品的47个视图。
|
数据可视化 iOS开发
iOS 开发,什么是 Interface Builder(IB)?如何使用 IB 构建用户界面?
iOS 开发,什么是 Interface Builder(IB)?如何使用 IB 构建用户界面?
376 4
|
移动开发 JavaScript 小程序
vant4的基础用法
基于vue3和ts平台来使用 这篇文章会手把手的教你如何用vant开发h5
966 0
vant4的基础用法
|
Web App开发 JSON 缓存
HTTP的请求方法,空行,body,介绍请求报头的内部以及粘包问题
HTTP的请求方法,空行,body,介绍请求报头的内部以及粘包问题
|
存储
ES聚合查询详解(四):管道聚合
ES聚合查询详解(四):管道聚合
772 0
ES聚合查询详解(四):管道聚合