深入探討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/zh-hant/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

發表回復

登錄後才能評論