博客
关于我
longAdder源码解析
阅读量:792 次
发布时间:2023-02-06

本文共 2579 字,大约阅读时间需要 8 分钟。

Striped64:LongAdder并发控制机制深度解析

Striped类概述

Striped类是LongAdder实现并发控制的核心组件,主要采用了一种独特的缓存机制来解决多线程环境下的竞争问题。类图如下:

package cn.knightzz.atomic;import lombok.extern.slf4j.Slf4j;import java.util.concurrent.atomic.AtomicInteger;/** * @author 王天赐 * @title: Striped64 * @projectName hm-juc-codes * @description: Striped64用于实现LongAdder的并发控制 * @website http://knightzz.cn/ * @github https://github.com/knightzz1998 * @create: 2022-08-08 20:32 */@Slf4j(topic = "Striped64")public class Striped64 {    // 累加单元数组, 懒惰初始化    transient volatile Cell[] cells;    // 基础值, 如果没有竞争, 则用 cas 累加这个域    transient volatile long base;    // 在 cells 创建或扩容时, 置为 1, 表示加锁    transient volatile int cellsBusy;    // 可用cpu数量    static final int NCPU = Runtime.getRuntime().availableProcessors();}

Striped64的核心机制

Striped64通过将内存划分为多个缓存行,利用每个线程独有的随机探测器(Probe)来分布处理累加请求,避免了传统的锁机制在高并发场景下的性能瓶颈。

CAS锁机制

Striped64采用了CAS(比较与交换)机制来实现锁。具体实现如下:

public class CasLock {    private static AtomicInteger state = new AtomicInteger(0);    public static void lock() {        while (true) {            if (state.compareAndSet(0, 1)) {                break;            }        }    }    public static void unlock() {        state.set(0);    }}

Striped64的Cell实现

Cell类是Striped64的核心单元,主要负责存储累加值并支持原子性更新。其实现如下:

public class Cell {    volatile long value;    Cell(long x) {        value = x;    }    final boolean cas(long cmp, long val) {        return UNSAFE.compareAndSwapLong(this, valueOffset, cmp, val);    }    private static final sun.misc.Unsafe UNSAFE;    private static final long valueOffset;    static {        try {            UNSAFE = sun.misc.Unsafe.getUnsafe();            Class
ak = Cell.class; valueOffset = UNSAFE.objectFieldOffset(ak.getDeclaredField("value")); } catch (Exception e) { throw new Error(e); } }}

Striped64的缓存与内存机制

Striped64通过将内存划分为多个64字节的缓存行,每个缓存行对应一个Cell对象。这种机制能够显著提升性能,原因如下:

  • 缓存一致性:当一个CPU核心修改了某个缓存行中的数据时,其他CPU核心必须通过缓存一致性机制确保其缓存行的数据一致。
  • 缓存行划分:一个缓存行通常可以存储多个Cell对象(如8个Cell对象占用一个缓存行)。
  • 数据分布:通过随机探测器(Probe),每个线程对应一个独特的Cell对象,避免多线程竞争同一Cell对象。
  • Striped64的累加方法

    Striped64的累加方法主要包括以下步骤:

  • 初始化检查:首先检查是否已经初始化了cells数组。如果尚未初始化,则直接在base上进行累加。
  • 原子性更新:如果cells数组已初始化,通过CAS机制尝试更新对应的Cell对象的值。如果成功,则完成累加操作;如果失败,则进入扩容流程。
  • 扩容机制:当多个线程竞争激烈时,Striped64会自动扩容cells数组的大小,以减少重试次数和提高性能。
  • 性能优化策略

    Striped64通过以下机制实现了对高并发场景下的性能优化:

  • 懒初始化:cells数组只有在检测到竞争时才会被初始化,减少了内存占用。
  • 随机探测器:通过ThreadLocalRandom生成随机探测器值,确保每个线程对应的Cell对象分布均匀。
  • 缓存行分配:每个缓存行存储多个Cell对象,充分利用CPU缓存带宽,避免多线程竞争同一Cell对象。
  • 总结

    Striped64通过创新的缓存与内存管理机制,结合CAS锁和懒初始化策略,实现了对高并发场景下的性能优化。其核心思想在于将内存划分为多个缓存行,每个线程对应一个独特的Cell对象,从而避免了传统锁机制的性能瓶颈。这种设计理念在现代并发控制中具有重要的参考价值。

    转载地址:http://jnufk.baihongyu.com/

    你可能感兴趣的文章
    localhost 目前无法处理此请求。 HTTP ERROR 500
    查看>>
    localhost与127.0.0.1,本地主机与IP地址之争!
    查看>>
    localhost:5000在MacOS V12(蒙特利)中不可用
    查看>>
    locals 和 globals
    查看>>
    localStorage使用总结
    查看>>
    location.href的几种用法
    查看>>
    location.href表示当前访问的网址url
    查看>>
    location优先级别问题
    查看>>
    Lock wait timeout exceeded; try restarting transaction mysql报错
    查看>>
    Lock 锁底层实现
    查看>>
    lock和synchronized区别
    查看>>
    Lock和synchronized区别(以及Lock的使用)
    查看>>
    Lock锁精讲
    查看>>
    Locust性能测试 —— 环境搭建及使用
    查看>>
    Locust简介与使用教程
    查看>>
    lodash常用API
    查看>>
    Log4j 1使用教程
    查看>>
    Log4j XML 配置
    查看>>
    Log4j 日志级别
    查看>>
    Log4j 漏洞测试
    查看>>