并发编程原理与实战(二十九)原子引用类型详解、ABA问题原理与防护策略

线程安全三要素与四大防护手段实战解析 线程安全是多线程编程的核心基础概念,本质源于Java内存模型(JMM)对原子性、可见性、有序性的约束。其底层原理涉及CPU缓存一致性、指令重排序与工作内存同步机制,技术价值在于保障共享状态在高并发下的正确性与可预测性。典型应用场景包括计数器累加、状态标志控制、单例初始化及上下文隔离等。本文聚焦i++非原子性、volatile可见性失效、双重检查锁定重排序等真实并发陷阱,结合synchronized、ReentrantLock、CAS和ThreadLocal四大手段,剖析各自适用边界与典型误用,直击面试与生产 阅读详情

上一篇学习了AtomicInteger的核心api,本文继续学习原子引用类型。

CAS示例

AtomicLong、AtomicBoolean的核心方法和AtomicInteger的核心api类似,主要是提供了原子增减、比较交换等方法。我们对AtomicInteger、AtomicBoolean的CAS方法进行举例,其他方法不再详解。

(1)原子长整型对象

public class AtomicCas {
    //原子长整型对象
    private static AtomicLong counter = new AtomicLong(0);
    public static void main(String[] args) throws InterruptedException {
        System.out.println("before cas result: " + counter.get());
        System.out.println("cas result:"+counter.compareAndSet(0, 1));
        System.out.println("after cas result: " + counter.get());
    }
}

运行结果:

before cas result: 0
cas result:true
after cas result: 1

从运行结果可以看出,上面的代码中,原子长整型对象counter的初始值是0,调用compareAndSet()方法后,值被设置为1。

(2)原子布尔对象

public class AtomicCas {
    //原子布尔对象
    private static AtomicBoolean ret = new AtomicBoolean(false);
    public static void main(String[] args) throws InterruptedException {
        System.out.println("before cas result: " + ret.get());
        System.out.println("cas result:"+ret.compareAndSet(false, true));
        System.out.println("after cas result: " + ret.get());
    }
}

运行结果:

before cas result: false
cas result:true
after cas result: true

从运行结果可以看出,上面的代码中,原子布尔对象ret的初始值是false,调用compareAndSet()方法后,值被设置为true。

AtomicInteger、AtomicLong、AtomicBoolean均是基本数据类型对应的原子类,如果要原子更新引用类型的变量,则需要使用原子引用类型了。

原子引用类型

AtomicReference是用于实现引用对象原子操作的线程安全工具类。其核心方法可分为基础操作、原子更新和函数式编程增强三类。

基础操作方法

(1)构造方法‌

AtomicReference():初始化为null引用。

/**
 * Creates a new AtomicReference with null initial value.
 */
public AtomicReference() {
}

AtomicReference(V initialValue):初始化指定对象引用。

/**
 * Creates a new AtomicReference with the given initial value.
 *
 * @param initialValue the initial value
 */
public AtomicReference(V initialValue) {
    value = initialValue;
}

(2)值存取‌

get():获取当前引用值。

/**
 * Returns the current value,
 * with memory effects as specified by {@link VarHandle#getVolatile}.
 *
 * @return the current value
 */
public final V get() {
    return value;
}

set(V newValue):无条件更新引用。

/**
 * Sets the value to {@code newValue},
 * with memory effects as specified by {@link VarHandle#setVolatile}.
 *
 * @param newValue the new value
 */
public final void set(V newValue) {
    value = newValue;
}

原子更新方法

(1)CAS操作‌

compareAndSet(V expect, V update):核心方法,当当前值等于expect时原子更新为update,返回是否成功。

/**
 * Atomically sets the value to {@code newValue}
 * if the current value {@code == expectedValue},
 * with memory effects as specified by {@link VarHandle#compareAndSet}.
 *
 * @param expectedValue the expected value
 * @param newValue the new value
 * @return {@code true} if successful. False return indicates that
 * the actual value was not equal to the expected value.
 */
public final boolean compareAndSet(V expectedValue, V newValue) {
    return VALUE.compareAndSet(this, expectedValue, newValue);
}

(2)复合操作‌

getAndSet(V newValue):原子获取当前值并更新,返回旧值。

/**
 * Atomically sets the value to {@code newValue} and returns the old value,
 * with memory effects as specified by {@link VarHandle#getAndSet}.
 *
 * @param newValue the new value
 * @return the previous value
 */
@SuppressWarnings("unchecked")
public final V getAndSet(V newValue) {
    return (V)VALUE.getAndSet(this, newValue);
}

compareAndExchange(V expect, V update):JDK9新增,类似CAS但返回原值而非布尔结果。

/**
 * Atomically sets the value to {@code newValue} if the current value,
 * referred to as the <em>witness value</em>, {@code == expectedValue},
 * with memory effects as specified by
 * {@link VarHandle#compareAndExchange}.
 *
 * @param expectedValue the expected value
 * @param newValue the new value
 * @return the <em>witness value</em>, which will be the same as the
 * expected value if successful
 * @since 9
 */
public final V compareAndExchange(V expectedValue, V newValue) {
    return (V)VALUE.compareAndExchange(this, expectedValue, newValue);
}

witness value即expected value,也就是期望的值。

函数式编程增强(JDK8+)

(1)一元操作‌

updateAndGet(UnaryOperator updateFunction):以原子方式使用给定函数的运算结果更新当前值,并返回更新后的值。

/**
 * Atomically updates (with memory effects as specified by {@link
 * VarHandle#compareAndSet}) the current value with the results of
 * applying the given function, returning the updated value. The
 * function should be side-effect-free, since it may be re-applied
 * when attempted updates fail due to contention among threads.
 *
 * @param updateFunction a side-effect-free function
 * @return the updated value
 * @since 1.8
 */
public final V updateAndGet(UnaryOperator<V> updateFunction) {
    V prev = get(), next = null;
    for (boolean haveNext = false;;) {
        if (!haveNext)
            next = updateFunction.apply(prev);
        if (weakCompareAndSetVolatile(prev, next))
            return next;
        haveNext = (prev == (prev = get()));
    }
}

所谓一元操作(Unary Operation)是指‌仅接受一个操作数‌的运算或函数。java 中常见的一元操作有:

  • Lambda表达式:x -> x * 2,如更新乘以2操作后的值:updateAndGet(x -> x * 2)。
  • 方法引用:String::toUpperCase
  • UnaryOperator接口:该接口是java.util.function包下的函数式接口,专用于对单个操作数进行运算并返回同类型结果

所以上述方法接收的是一个函数式的参数,并将函数的运算结果作为更新值,并返回更新后的值。该函数应是无副作用的,因为在多线程竞争导致更新尝试失败时,函数可能会被重新执行。

getAndUpdate(UnaryOperator updateFunction):以原子方式使用给定函数的运算结果更新当前值,并返回旧的值。

/**
 * Atomically updates (with memory effects as specified by {@link
 * VarHandle#compareAndSet}) the current value with the results of
 * applying the given function, returning the previous value. The
 * function should be side-effect-free, since it may be re-applied
 * when attempted updates fail due to contention among threads.
 *
 * @param updateFunction a side-effect-free function
 * @return the previous value
 * @since 1.8
 */
public final V getAndUpdate(UnaryOperator<V> updateFunction) {
    V prev = get(), next = null;
    for (boolean haveNext = false;;) {
        if (!haveNext)
            next = updateFunction.apply(prev);
        if (weakCompareAndSetVolatile(prev, next))
            return prev;
        haveNext = (prev == (prev = get()));
    }
}

(2)二元操作‌

accumulateAndGet(V x, BinaryOperator accumulatorFunction):以原子方式更新当前值,通过将当前值与给定值作为参数输入指定函数,用函数返回值更新原值。返回更新后的值。

/**
 * Atomically updates (with memory effects as specified by {@link
 * VarHandle#compareAndSet}) the current value with the results of
 * applying the given function to the current and given values,
 * returning the updated value. The function should be
 * side-effect-free, since it may be re-applied when attempted
 * updates fail due to contention among threads.  The function is
 * applied with the current value as its first argument, and the
 * given update as the second argument.
 *
 * @param x the update value
 * @param accumulatorFunction a side-effect-free function of two arguments
 * @return the updated value
 * @since 1.8
 */
public final V accumulateAndGet(V x,BinaryOperator<V> accumulatorFunction) {
    V prev = get(), next = null;
    for (boolean haveNext = false;;) {
        if (!haveNext)
            next = accumulatorFunction.apply(prev, x);
        if (weakCompareAndSetVolatile(prev, next))
            return next;
        haveNext = (prev == (prev = get()));
    }
}

所谓二元操作(Binary Operation)是指需要两个操作数(输入)才能完成运算的操作。所以该函数接收的是两个参数,第一个参数是要更新的值;第二个参数是BinaryOperator类型函数式参数,BinaryOperator是Java 8引入的函数式接口,位于java.util.function包中,专为处理两个相同类型操作数的运算而设计。该函数应满足无副作用特性,因为在多线程竞争导致更新失败时可能被重复执行。

getAndAccumulate(V x, BinaryOperator accumulatorFunction):以原子方式更新当前值,通过将当前值与给定值作为参数输入指定函数,用函数返回值更新原值。返回旧的值。

/**
 * Atomically updates (with memory effects as specified by {@link
 * VarHandle#compareAndSet}) the current value with the results of
 * applying the given function to the current and given values,
 * returning the previous value. The function should be
 * side-effect-free, since it may be re-applied when attempted
 * updates fail due to contention among threads.  The function is
 * applied with the current value as its first argument, and the
 * given update as the second argument.
 *
 * @param x the update value
 * @param accumulatorFunction a side-effect-free function of two arguments
 * @return the previous value
 * @since 1.8
 */
public final V getAndAccumulate(V x,
                                BinaryOperator<V> accumulatorFunction) {
    V prev = get(), next = null;
    for (boolean haveNext = false;;) {
        if (!haveNext)
            next = accumulatorFunction.apply(prev, x);
        if (weakCompareAndSetVolatile(prev, next))
            return prev;
        haveNext = (prev == (prev = get()));
    }
}

AtomicReference 典型例子

原子更新引用对象

原子更新自定义对象引用,确保多线程环境下对象替换的线程安全。

@Getter
@Setter
class OrderInfo {
    private String address;
    private float fee;

    public OrderInfo(String address, float age) {
        this.fee = age;
        this.address = address;
    }
}

public class AtomicReferenceTest {
    public static void main(String[] args) {
        AtomicReference<OrderInfo> atomicReference = new AtomicReference<>();
        OrderInfo order = new OrderInfo("北京天安门广场", 100);
        atomicReference.set(order);
        OrderInfo updateOrder = new OrderInfo("上海虹桥机场", 200);
        // 原子替换
        atomicReference.compareAndSet(order, updateOrder);
        // 输出上海虹桥机场
    System.out.println(atomicReference.get().getAddress()+","+atomicReference.get().getFee());
    }
}

运行结果:上海虹桥机场,200.0

无锁并发栈

需求:定义一个栈,100个线程并发压栈,每个线程入栈1000个元素,确保结果的正确性。

代码实现:

通过AtomicReference实现线程安全的栈结构,利用CAS操作保证push和pop操作的原子性。栈顶节点通过AtomicReference<Node>维护,compareAndSet确保并发修改时仅有一个线程成功更新栈顶。

public class ConcurrentStack<T> {
    //栈元素
    private static class Node<T> {
        final T item;
        Node<T> next;

        Node(T item) {
            this.item = item;
        }
    }

    //栈顶元素
    private final AtomicReference<Node<T>> top = new AtomicReference<>();

    //入栈
    public void push(T item) {
        Node<T> newHead = new Node<>(item);
        Node<T> oldHead;
        do {
            oldHead = top.get();
            newHead.next = oldHead;
            //栈顶修改为新的节点
        } while (!top.compareAndSet(oldHead, newHead));
    }

    //出栈
    public T pop() {
        Node<T> oldHead;
        Node<T> newHead;
        do {
            oldHead = top.get();
            if (oldHead == null) return null;
            newHead = oldHead.next;
        } while (!top.compareAndSet(oldHead, newHead));
        return oldHead.item;
    }

    public static void main(String[] args) throws InterruptedException {
        final ConcurrentStack<Integer> stack = new ConcurrentStack<>();
        Thread[] threads = new Thread[100];

        // 100线程并发压栈,每个线程入栈1000个元素,结果应该是100000
        for (int i = 0; i < 100; i++) {
            final int threadId = i;
            threads[i] = new Thread(() -> {
                for (int j = 0; j < 1000; j++) {
                    stack.push(threadId * 1000 + j);
                }
            });
            threads[i].start();
        }

        // 等待所有线程完成
        for (Thread t : threads) t.join();

        // 验证结果
        int count = 0;
        while (stack.pop() != null) count++;
        // 应输出100000
        System.out.println("Total elements: " + count);
    }
}

运行结果:Total elements: 100000。该实现通过10万次并发操作验证了结果的正确性。

ABA问题与带邮戳的原子引用对象

在原子更新引用对象这个例子中,如果一个线程更新了引用对象后,另一个线程又把引用对象更新回原来的值(也就是ABA问题),代码如下:

@Getter
@Setter
class OrderInfo {
    private String address;
    private float fee;

    public OrderInfo(String address, float age) {
        this.fee = age;
        this.address = address;
    }
}

public class AtomicReferenceTest {
    public static void main(String[] args) throws InterruptedException {
        AtomicReference<OrderInfo> atomicReference = new AtomicReference<>();
        OrderInfo order = new OrderInfo("北京天安门广场", 100);
        atomicReference.set(order);
        OrderInfo updateOrder = new OrderInfo("上海虹桥机场", 200);
        OrderInfo updateOrder2 = new OrderInfo("北京天安门广场", 100);

        Thread t1 = new Thread(() -> {
            // 原子替换
            atomicReference.compareAndSet(order, updateOrder);
            // 输出上海虹桥机场
            System.out.println("t1:" + atomicReference.get().getAddress() + "," + atomicReference.get().getFee());
        });
        t1.start();
        t1.join();

        Thread t2 = new Thread(() -> {
            // 原子替换
            atomicReference.compareAndSet(updateOrder, updateOrder2);
            // 输出北京天安门广场
            System.out.println("t2:" + atomicReference.get().getAddress() + "," + atomicReference.get().getFee());
        });
        t2.start();
        t2.join();
    }
}

输出结果:

t1:上海虹桥机场,200.0
t2:北京天安门广场,100.0

针对这种情况,怎么知道引用对象有没有被修改过呢?为了解决这个问题,又引入了带邮戳的原子引用类型AtomicStampedReference。

构造函数

/**
 * Creates a new {@code AtomicStampedReference} with the given
 * initial values.
 *
 * @param initialRef the initial reference
 * @param initialStamp the initial stamp
 */
public AtomicStampedReference(V initialRef, int initialStamp) {
    pair = Pair.of(initialRef, initialStamp);
}

如上所示,AtomicStampedReference只有一个构造函数,创建带邮戳的原子引用类型对象的时候,需要指定对象的初始值和版本号。

获取版本号

通过getStamp()方法获取当前引用对象的版本号。

/**
 * Returns the current value of the stamp.
 *
 * @return the current value of the stamp
 */
public int getStamp() {
    return pair.stamp;
}

CAS方法

其compareAndSet()源码如下:

/**
 * Atomically sets the value of both the reference and stamp
 * to the given update values if the
 * current reference is {@code ==} to the expected reference
 * and the current stamp is equal to the expected stamp.
 *
 * @param expectedReference the expected value of the reference
 * @param newReference the new value for the reference
 * @param expectedStamp the expected value of the stamp
 * @param newStamp the new value for the stamp
 * @return {@code true} if successful
 */
public boolean compareAndSet(V   expectedReference,
                             V   newReference,
                             int expectedStamp,
                             int newStamp) {
    Pair<V> current = pair;
    return
        expectedReference == current.reference &&
        expectedStamp == current.stamp &&
        ((newReference == current.reference &&
          newStamp == current.stamp) ||
         casPair(current, Pair.of(newReference, newStamp)));
}

该方法原子性地同时设置引用和版本戳的值,仅当当前引用等于预期引用且当前版本戳等于预期版本戳时才会更新。

  • @param expectedReference 引用的预期值
  • @param newReference 引用的新值
  • @param expectedStamp 版本戳的预期值
  • @param newStamp 版本戳的新值
  • @return {@code true} 表示操作成功

根据版本号获取引用对象

获取引用对象的值的时候则需要传入当前对象持有的版本号。

/**
 * Returns the current values of both the reference and the stamp.
 * Typical usage is {@code int[1] holder; ref = v.get(holder); }.
 *
 * @param stampHolder an array of size of at least one.  On return,
 * {@code stampholder[0]} will hold the value of the stamp.
 * @return the current value of the reference
 */
public V get(int[] stampHolder) {
    Pair<V> pair = this.pair;
    stampHolder[0] = pair.stamp;
    return pair.reference;
}

原子更新带版本号的引用对象

对于上面的例子,用AtomicStampedReference来实现。

@Getter
@Setter
class OrderInfo {
    private String address;
    private float fee;

    public OrderInfo(String address, float age) {
        this.fee = age;
        this.address = address;
    }
}

public class AtomicReferenceTest {
    public static void main(String[] args) throws InterruptedException {
        OrderInfo order = new OrderInfo("北京天安门广场", 100);
        AtomicStampedReference<OrderInfo> atomicReference = new AtomicStampedReference<>(order, 1);

        OrderInfo updateOrder = new OrderInfo("上海虹桥机场", 200);
        OrderInfo updateOrder2 = new OrderInfo("北京天安门广场", 100);

        //用于存储方法返回的版本戳值
        int[] stampHolder = new int[1];
        Thread t1 = new Thread(() -> {
            // 原子替换,版本号同步加1
            atomicReference.compareAndSet(order, updateOrder, atomicReference.getStamp(), atomicReference.getStamp() + 1);
            // 输出上海虹桥机场
            System.out.println("t1:" + atomicReference.get(stampHolder).getAddress() + "," + atomicReference.get(stampHolder).getFee() + "," + stampHolder[0]);
        });
        t1.start();
        t1.join();

        Thread t2 = new Thread(() -> {
            // 原子替换,版本号同步加1
            atomicReference.compareAndSet(updateOrder, updateOrder2, atomicReference.getStamp(), atomicReference.getStamp() + 1);
            // 输出北京天安门广场
            System.out.println("t2:" + atomicReference.get(stampHolder).getAddress() + "," + atomicReference.get(stampHolder).getFee() + "," + stampHolder[0]);
        });
        t2.start();
        t2.join();
    }
}

运行结果:

t1:上海虹桥机场,200.0,2
t2:北京天安门广场,100.0,3

从运行结果可以看出,线程t2拿到的引用对象虽然值还是原始的值,但是其版本号已经是3了,说明引用对象已经被修改过然后又修改回原始的值了。

C++并发编程中ABA问题的成因与三大解决方案详解 在并发编程领域,CAS(Compare-And-Swap)操作是实现无锁数据结构的核心原子指令,它通过比较内存值并决定是否交换来保证操作的原子性。然而,CAS操作存在一个经典的并发陷阱——ABA问题,即一个值从A变为B后又变回A,导致CAS操作在逻辑上错误地成功。这一问题源于CAS只检查值的相等性,而无法感知值在比较与交换期间是否经历了状态轮回。在C++中,由于内存分配器会积极复用已释放的内存,ABA问题极易引发悬垂指针访问和未定义行为,严重威胁内存安全。为解决此问题,业界主要采用三种技术:带标签指针通过扩 阅读详情

相关推荐

C++面试八股文常见错误勘误:从constexpr到ABA问题

C++作为高性能系统级编程语言,其语法细节与并发模型始终是开发者关注的焦点。在面试准备中,常因资料错误导致对constexpr引入版本、CAS操作与ABA问题等核心概念产生误解。理解这些底层原理不仅有助于写出更健壮的代码,也能在工程实践中正确运用内存模型、原子操作与智能指针。从基础语法到多线程编程,再到算法复杂度与设计模式,系统梳理这些高频考点的本质,能帮助开发者避开常见误区,真正提升技术判断力与工程实践能力。本文基于实际面试经验,对多个常见错误进行逐一勘误,并给出更符合现代C++标准的理解方式,助你构建更

weixin_30861797的博客 555

终极指南:5分钟掌握Forza Painter车辆涂装转换工具

还在为《极限竞速:地平线》系列游戏中复杂的车辆涂装设计而头疼吗?Forza Painter这款革命性的开源工具彻底改变了游戏体验,让你能够将任何图片一键转换为专业的车辆涂装!无论你是想展示个性照片、复刻经典艺术作品,还是创造独特的网络迷因涂装,这款强大的车辆涂装转换工具都能帮你轻松实现。 ## 🚗 什么是Forza Painter? Forza Painter是一款专为《极限竞速:地平线4》

gitblog_00583的博客 397

深入解析C++原子操作与CAS:从i++陷阱到无锁编程实战

在多线程编程中,数据竞争是导致程序行为不确定的常见根源,其本质在于多个线程对共享数据的非原子访问。为了解决这一问题,现代编程语言提供了原子操作这一底层同步原语,它通过硬件指令保证特定操作的不可分割性,从而避免了传统互斥锁带来的性能开销。原子操作的核心技术价值在于实现了细粒度的同步,为构建高性能并发系统提供了基础。其中,比较并交换(CAS)操作是实现无锁数据结构的基石,它通过乐观并发控制策略,允许线程在不获取锁的情况下安全地更新共享数据,广泛应用于计数器、自旋锁、无锁队列等场景。理解原子操作与CAS的底层硬件

weixin_34183910的博客 408

深入浅出Java多线程:CAS原理与JUC组件实战指南

CAS和JUC组件就像并发世界的阴阳两极——一个负责微观原子操作,一个提供宏观并发控制。没有银弹!在实际项目中,一定要根据具体场景选择合适的并发策略。建议大家在IDE里多写几个demo体验下,毕竟纸上得来终觉浅嘛~

agiledev1的博客 746

AI原生行为分析系统的安全防护策略

本报告系统解析AI原生行为分析系统的安全防护策略,覆盖从理论框架到工程实践的全生命周期。通过第一性原理拆解AI行为分析系统的核心脆弱点(如对抗攻击、数据投毒、模型窃取),构建层次化防护架构(数据-模型-服务-监控四维防护体系),结合数学形式化(如对抗扰动的Lp范数约束)、代码实现(如PyTorch对抗训练示例)、可视化模型(Mermaid架构图)及真实案例(金融风控系统攻击事件),为技术团队提供可落地的安全设计指南。

操作系统内核探秘的博客 738

WPS JS宏实战:批量调整200个Word表格格式的避坑指南(附完整代码)

本文提供了一份详尽的WPS JS宏实战指南,针对批量调整大量Word表格格式的需求。文章深入解析了如何利用JS宏自动化设置字体、行距和边框,并重点解决了常见的“首行访问报错”等核心难题,附有可直接使用的完整代码,帮助用户显著提升文档处理效率。

weixin_29280219的博客 429

深入理解无锁编程:从CAS原理到ABA问题解决方案

并发编程中,锁机制虽然保证了数据安全,但在高竞争场景下可能引发性能瓶颈。无锁编程通过原子指令(如CAS)实现非阻塞同步,提升系统吞吐量。其核心原理是利用硬件支持的原子操作,让线程通过尝试-失败-重试循环更新共享数据,避免线程挂起开销。然而,无锁设计面临ABA问题的经典挑战——即指针地址复用导致的数据一致性问题。解决ABA问题需引入版本号或标签指针等机制,确保CAS检查值的唯一性。在C++工程实践中,使用std::shared_ptr的引用计数可天然防止内存复用,是兼顾安全性与开发效率的实用方案。无锁数据结构

weixin_34006468的博客 302

STM32F4系列HAL库配置定时器实验——输入捕获

STM32F4系列HAL库配置定时器实验——输入捕获 输入捕获简单讲解 输入捕获模式可以用来测量脉冲宽度或者测量频率。我们以测量周期和频率为例,用一个简图来说明输入捕获的原理 假定定时器工作在向上计数模式, 图中 t1~t2 时间,就是我们需要测量的高电平时间。测量方法如下:首先设置定时器通道 x 为 上升沿捕获,这样,t1 时刻,就会捕获到当前的 CNT 值,然后立即清零 CNT,并设置通道 x为下降沿捕获,这样到 t2 时刻,又会发生捕获事件,得到此时的 CNT 值,记为 CCRx2。这样,根据定时器

azs0504的博客 9285

Java并发编程实战深入揭秘线程池优化与高并发场景下的同步策略设计

若任务具有突发性特性,需通过扩展线程数(`maximumPoolSize > corePoolSize`)和灵活的拒绝策略(RejectedExecutionHandler)实现弹性扩容。本文将从线程池的核心原理出发,结合生产级场景,深入探讨其优化策略及同步机制的实现方法,为开发者提供可落地的实践方案。通过`handle()`, `whenComplete()`等合成操作符构建可靠的异步链路,注意处理未检查异常和超时控制。将粗粒度的类锁改为基于业务对象的细粒度锁,通过`LockToken`策略降低锁竞争。

sxmJDEkj的博客 814

RAGFlow本地部署遇阻:解析进度卡顿的排查与修复指南

本文针对RAGFlow本地部署中常见的文档解析进度卡顿问题,提供了详细的排查与修复指南。核心原因是模型下载网络受阻,解决方案是通过修改环境配置文件,将模型下载源切换至国内镜像站,从而快速解决解析停滞问题。

weixin_29297127的博客 341

夏令营纪实——东南大学计科院&PALM实验室面试全解析

本文详细解析了东南大学计科院与PALM实验室夏令营的面试全流程,包括前期准备、技术考察、项目经验深挖等关键环节。特别针对自然语言处理(NLP)和机器学习(ML)领域的高频问题提供应对策略,帮助申请者提升面试表现。文章还分享了实用的准备技巧和面试经验,为有意向参加该夏令营的学生提供宝贵参考。

convnet3designer的博客 459

别再盲目投广告!亚马逊ABA关键词运营:从流量精准定位到ROI翻倍的实战方案

在亚马逊运营中有不少卖家陷入“重广告、轻关键词”误区,认为加大预算就能提升自然排名,亚马逊自然排名核心是“关键词匹配度与转化效率”,而亚马逊品牌分析(ABA)工具,正是实现关键词精细化运营的关键。​。

2501_90930635的博客 816

高通SDX35平台 modem启动异常分析

SDX35 MIFI项目在生产时出现modem反复重启问题。经排查发现是modem在初始化GNSS模块时访问了不存在的硬件地址导致崩溃,原因是产线使用的SDX35 000-AB型号芯片阉割了GNSS功能,而本地测试使用的AA型号支持该功能。解决方案是通过修改modem编译选项,采用高通新提供的genlmm2选项(保留IMS和SMS功能但去除GNSS支持),最终解决了启动异常问题并满足VZW认证需求。

四儿家的小祖宗的博客 273

乐观锁的ABA困局:版本号机制与Java原子类的救赎之路

本文深入探讨了乐观锁中的ABA问题及其解决方案,重点介绍了版本号机制和Java原子类`AtomicStampedReference`的应用。通过CAS机制的分析和实战案例,展示了如何在高并发系统中避免ABA陷阱,提升线程安全性与性能。文章还对比了不同Java原子类的特性,为开发者提供了可靠的并发编程实践指南。

p4q5r6s7t的博客 153

建立时间与保持时间

建立时间与保持时间的计算 文章目录1、建立时间与保持时间概述及模型2、寄存器之间数据传输时建立时间与保持时间3、寄存器之间数据传输时建立时间余量与保持时间余量计算4、 FPGA允许的最大时钟频率或最小时钟周期5、计算FPGA时钟所允许的最大频率或最小时钟周期6、违反建立和保持时间会发生什么? 1、建立时间与保持时间概述及模型 建立时间(Tsu): 在时钟采样之前,输入必须稳定一段时间,该时间量称为建立时间。 理想最优建立时间: 保持时间(Th): 在时钟沿之后输入到触发器稳定所需的最短时间。 理想最优

Crazzy_M的博客 3万+

YOLOv11 改进 - 特征融合 | SSFF+TPE+CPAM 协同,ASF-YOLO 三重模块破解密集小目标分割难题

本文介绍了基于注意力尺度序列融合的ASF - YOLO模型在YOLOv11中的结合应用。ASF - YOLO旨在实现准确快速的细胞实例分割,结合空间和尺度特征,引入SSFF模块增强多尺度信息提取能力,TFE模块融合不同尺度特征图,CPAM整合前两者以关注信息丰富通道和小物体。我们将ASF - YOLO相关模块集成进YOLOv11,替代原有的部分特征融合模块,实现更高效的特征提取与融合。实验证明,YOLOv11 - ASFYOLO在细胞实例分割任务中表现出色,展现了该模型在深度学习中的广泛应用前景。

魔改工程师的博客 1256

推荐文章:C11无锁栈库 —— 高效并发编程新选择

推荐文章:C11无锁栈库 —— 高效并发编程新选择 1、项目介绍 在并发编程的世界里,效率是关键。为此,我们向您推荐一个使用C11标准原子操作(stdatomic.h)实现的无锁栈(Lock-free Stack)—— C11 Lock-free Stack Demo。这个小型库旨在提供一种高效、线程安全的数据结构,帮助您构建高性能的多线程应用。 项目灵感来源于《C11无锁栈》一文,它详尽解释了如...

gitblog_00090的博客 511

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

大厂Java面试核心:基础原理与实战能力解析

Java作为企业级开发的主流语言,其底层原理和工程实践能力是技术面试的核心考察点。从JVM内存模型到并发编程机制,这些基础概念构成了Java技术体系的基石。理解HashMap扩容策略、锁升级过程等原理级问题,不仅能展现知识深度,更能体现解决高并发、分布式场景的实际能力。大厂面试特别关注候选人对GC调优、线程安全等问题的实战经验,这些技能直接影响系统性能和稳定性。通过分析典型面试题如秒杀系统设计、性能优化方案等,可以系统性地掌握分布式架构和工程实践要点。

weixin_33981932的博客 346

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

【Java并发编程核心技巧】:AtomicInteger原子操作的5大应用场景与性能优化秘籍

掌握Java并发编程关键技巧,深入解析Java并发AtomicInteger原子操作的5大应用场景与性能优化策略,涵盖计数器、状态标志等实用案例,提升线程安全与执行效率,值得收藏。

AlgoInk的博客 452

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

《Java并发编程实战锁优化、线程安全与高吞吐量设计之道》

但调优需遵循“60%关注热点,30%关注调用链,10%关注算法”的法则。实验表明,在纯粹计算任务中,无锁队列性能比synchronized提升3-5倍,但在GC频繁的环境反而可能因虚假唤醒降低性能,需根据具体场景选择。实测显示在10节点集群下,该方案可容忍3节点宕机仍保持强一致性,写入性能仅降低15%,相比Paxos算法提升吞吐量40%,成功平衡了可用性与一致性。在电商秒杀系统中,代码层使用原子类CAS操作,框架层采用Redis布隆过滤器限流,系统层设置熔断机制,共同构建抵御百万级并发的防护网络。

PemGvDdt的博客 809

AI提示词破防:原理剖析与防御策略实战

基于火山引擎豆包大模型,从零搭建一个实时语音通话应用。它不是简单的问答,而是需要你亲手打通 ASR(语音识别)→ LLM(大脑思考)→ TTS(语音合成)的完整 WebSocket 链路。对于想要掌握 AI 原生应用架构的同学来说,这是个绝佳的练手项目。架构理解:掌握实时语音应用的完整技术链路(ASR→LLM→TTS)技能提升:学会申请、配置与调用火山引擎AI服务定制能力:通过代码修改自定义角色性格与音色,实现“从使用到创造”从0到1构建生产级别应用,脱离Demo,点击打开。

2600_94959965的博客 375

Java AtomicInteger原子操作实战(从入门到精通的8个关键点)

掌握Java并发编程核心技巧,深入解析AtomicInteger原子操作。涵盖自增、比较并交换等方法,适用于高并发场景下的线程安全计数与状态控制,避免锁开销,提升性能。从原理到实战,8个关键点全面覆盖,值得收藏。

CompiLume的博客 352

【Java并发编程实战解锁多线程性能优化的三大核心策略】

p标签:锁的粒度越细,线程访问互斥资源的重叠率越低。集群环境实测案例表明,采用16分片的锁结构能使百线程下的冲突频率下降至传统单锁方案的7.8%。开发者可通过内存属性配置,将共享内存的原子操作降级为仅指令缓存同步,理论预期能降低35%的MESI总线流量。p标签:基于Compare-and-Swap的乐观锁策略可避免传统锁的阻塞开销,但需处理ABA问题。p标签:在RISC-V架构中,通过定义新CSR寄存器实现线程本地存储,可在硬件层绕过JVM的内存屏障指令,某实验验证表明可使CAS操作效率提升2.4倍。

fvBGweuL的博客 419

《Java并发编程艺术深入JUC框架与锁机制的底层实现与实战优化》

Java并发编程的核心挑战在于平衡线程同步的安全性与效率。此框架通过组件化设计(如`Lock`接口、`ConcurrentMap`)、AQS同步器(AbstractQueuedSynchronizer)以及底层CAS原子操作,构建了一套“既有高层抽象,又不牺牲底层性能”的解决方案。其本质是一个模板方法设计模式的实例:同步器(如`ReentrantLock`)实现`AQS`的`tryAcquire`和`tryRelease`方法,定义具体的加锁与解锁逻辑,而AQS负责维护同步状态、线程队列及阻塞/唤醒机制。

VtpjFpOn的博客 313

Java面试7天冲刺:高频考点与实战策略

Java作为企业级开发的主流语言,其技术栈深度和广度对开发者提出了较高要求。理解JVM内存模型、并发编程原理等核心机制,是构建高性能应用的基础。在分布式架构盛行的当下,掌握Redis、Spring等中间件和框架的底层实现,能够显著提升系统设计能力。通过结构化表达和工程化思维,开发者可以将复杂的技术原理转化为清晰的解决方案。本文基于Java技术栈的高频考点,结合JVM调优和并发编程等热词,提供了一套7天高效备战方案,涵盖知识图谱构建、模拟面试等实用技巧,帮助开发者在有限时间内系统化提升面试竞争力。

weixin_30256901的博客 345
上一篇: 开发避坑指南(48):Java Stream 判断List元素的属性是否包含指定的值
下一篇: 并发编程原理与实战(三十)原子操作进阶,原子数组与字段更新器精讲
帧栈
博客等级 码龄2年 335粉丝 120原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

帧栈

您的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值