深入探讨AtomicLong

在多线程编程中,要确保数据的可见性和正确性,最常见的方式是用锁来保证同步,但是锁会带来额外的开销,如频繁的拷贝、线程挂起与恢复等,而AtomicLong则是一种无锁的同步实现方式,能够保证线程安全,同时性能也非常不错。

一、AtomicLong就是原子操作

AtomicLong是Java.util.concurrent.atomic包下的一个类,它对一个长整型值进行原子操作,同时保证在多线程环境下的线程安全。在Java中,原子操作是一种不可分割、不可中断的操作,只有执行完毕或者不执行。

就是说:要么成功执行整个操作,要么就不执行,而不会出现执行了一半就被中断的情况,这对于高并发场景下的数据修改和读取是非常有用的。

二、AtomicLong的使用方法

AtomicLong类的常用方法主要有三种:

1. 原子更新基本类型

public final long getAndAdd(long delta)
public final long addAndGet(long delta)
public final long getAndIncrement()
public final long getAndDecrement()
public final long getAndSet(long newValue)

这五个方法都是原子性地对一个long类型的变量进行更新。其中,getAndAdd()方法是先获得当前值,再增加指定的值;addAndGet()方法相反,是先增加指定的值,再获得新的值;getAndIncrement()方法是先获得当前值,再自增;getAndDecrement()方法是先获得当前值,再自减;getAndSet()方法是先获得当前值,再设置新值。

2. 原子更新数组

public final int getAndAdd(int[] array, int index, int delta)
public final int addAndGet(int[] array, int index, int delta)
public final int getAndIncrement(int[] array, int index)
public final int getAndDecrement(int[] array, int index)
public final int getAndSet(int[] array, int index, int newValue)

这五个方法都是原子性地对一个指定下标的整型数组的元素进行更新,其他操作和上面的方法相似。

3. 原子更新:compareAndSet

public final boolean compareAndSet(long expect, long update)

compareAndSet()方法是一个CAS操作,即比较并交换。如果当前值和期望值相等,则更新它为新值,否则不进行任何操作。

三、AtomicLong的例子

1. 使用AtomicLong进行线程安全的计数器操作

public class Counter {
    private AtomicLong value = new AtomicLong(0L);

    public long getValue() {
        return value.get();
    }

    public void increment() {
        value.incrementAndGet();
    }

    public void add(long delta) {
        value.addAndGet(delta);
    }

    public void decrement() {
        value.decrementAndGet();
    }
}

在这个例子中,我们定义了一个计数器类,用于统计某一事件发生的次数。通过使用AtomicLong,我们保证了该计数器是线程安全的。可以看到,我们只需要调用AtomicLong类中提供的方法,就可以完成加减等操作。

2. 使用compareAndSet()方法进行锁的释放

public class SpinLock {
    private AtomicBoolean locked = new AtomicBoolean(false);

    public void lock() {
        boolean flag = false;

        while (!(flag = locked.compareAndSet(false, true))) {
            // 换成尝试去获取锁的代码
        }
    }

    public void unlock() {
        locked.set(false);
    }
}

在这个例子中,我们定义了一个自旋锁SpinLock,用于保护临界区代码的执行顺序。当线程需要进入临界区时,先调用lock()方法获取锁,如果锁被其他线程占用,则自旋等待。当线程执行完临界区代码后,调用unlock()方法释放锁,让其他线程可以获取锁。

四、总结

在多线程编程中,为了保证线程安全,一般需要使用锁等同步机制。但是,锁会带来额外的开销,影响程序的性能。而AtomicLong则是一种无锁的线程安全实现方式,它能够保证线程安全,并且性能非常出色。在实际应用中,可以根据需求使用AtomicLong的各种方法,也可以根据自己的需求实现自己的原子类。无论何种方式,只要遵循了原子操作的规则,就能够保证线程安全。

原创文章,作者:小蓝,如若转载,请注明出处:https://www.506064.com/n/283235.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
小蓝小蓝
上一篇 2024-12-22 08:07
下一篇 2024-12-22 08:07

相关推荐

  • 深入解析Vue3 defineExpose

    Vue 3在开发过程中引入了新的API `defineExpose`。在以前的版本中,我们经常使用 `$attrs` 和` $listeners` 实现父组件与子组件之间的通信,但…

    编程 2025-04-25
  • 深入理解byte转int

    一、字节与比特 在讨论byte转int之前,我们需要了解字节和比特的概念。字节是计算机存储单位的一种,通常表示8个比特(bit),即1字节=8比特。比特是计算机中最小的数据单位,是…

    编程 2025-04-25
  • 深入理解Flutter StreamBuilder

    一、什么是Flutter StreamBuilder? Flutter StreamBuilder是Flutter框架中的一个内置小部件,它可以监测数据流(Stream)中数据的变…

    编程 2025-04-25
  • 深入探讨OpenCV版本

    OpenCV是一个用于计算机视觉应用程序的开源库。它是由英特尔公司创建的,现已由Willow Garage管理。OpenCV旨在提供一个易于使用的计算机视觉和机器学习基础架构,以实…

    编程 2025-04-25
  • 深入了解scala-maven-plugin

    一、简介 Scala-maven-plugin 是一个创造和管理 Scala 项目的maven插件,它可以自动生成基本项目结构、依赖配置、Scala文件等。使用它可以使我们专注于代…

    编程 2025-04-25
  • 深入了解LaTeX的脚注(latexfootnote)

    一、基本介绍 LaTeX作为一种排版软件,具有各种各样的功能,其中脚注(footnote)是一个十分重要的功能之一。在LaTeX中,脚注是用命令latexfootnote来实现的。…

    编程 2025-04-25
  • 深入探讨冯诺依曼原理

    一、原理概述 冯诺依曼原理,又称“存储程序控制原理”,是指计算机的程序和数据都存储在同一个存储器中,并且通过一个统一的总线来传输数据。这个原理的提出,是计算机科学发展中的重大进展,…

    编程 2025-04-25
  • 深入理解Python字符串r

    一、r字符串的基本概念 r字符串(raw字符串)是指在Python中,以字母r为前缀的字符串。r字符串中的反斜杠(\)不会被转义,而是被当作普通字符处理,这使得r字符串可以非常方便…

    编程 2025-04-25
  • 深入了解Python包

    一、包的概念 Python中一个程序就是一个模块,而一个模块可以引入另一个模块,这样就形成了包。包就是有多个模块组成的一个大模块,也可以看做是一个文件夹。包可以有效地组织代码和数据…

    编程 2025-04-25
  • 深入剖析MapStruct未生成实现类问题

    一、MapStruct简介 MapStruct是一个Java bean映射器,它通过注解和代码生成来在Java bean之间转换成本类代码,实现类型安全,简单而不失灵活。 作为一个…

    编程 2025-04-25

发表回复

登录后才能评论