多線程(進階二:CAS)

目錄

一、CAS的簡單介紹

CAS邏輯(用偽代碼來描述)

二、CAS在多線程中簡單的使用

三、原子類自增的代碼分析

都看到這了,點個贊再走吧,謝謝謝謝謝


一、CAS的簡單介紹

CAS的全稱:“Compare And Swap”,字面意思是 “比較和交換”;一個CAS涉及到以下操作,有兩個寄存器:A,SwapB,還有內存的值:AddressC。

先判斷寄存器A是否和AddressC的值相同,相同,SwapB的值和AddressC的值進行交換,返回成功操作,否則返回失敗操作。這里的交換值我們也可以理解成賦值操作,因為寄存器中的值我們不關心,用完就丟掉了,只關心內存中的值。

CAS邏輯(用偽代碼來描述)

偽代碼:

這里有兩個寄存器:expectValue,swapValue,還有內存的值:address,初始化如圖:

進入if語句,判斷內存的值和寄存器e的值是否相等,如果相等,就交換寄存器swap和內存address的值,如圖:

如圖:

然后返回true,如果if條件不成立則返回false。

在計算機中,上述操作在計算機只是一條指令,因為單個指令的原因,所以CAS指令是原子的

CAS指令不涉及到加鎖,阻塞。基于CAS指令,合理使用的話,在多線程中,我們可以實現無鎖編程;因為之前我們討論并發編程的線程安全問題時,是通過加鎖,阻塞這樣方式解決線程安全問題,因為會有阻塞,所以性能也就會降低,用CAS指令實現無鎖編程,也能保證線程安全,不涉及到阻塞,這樣性能就能得到很大的提升,在多線程編程中打開了新世界的大門。


二、CAS在多線程中簡單的使用

因為CAS是CPU的指令,有的cpu可能不支持CAS,但主流的CPU(x86,arm...)都是支持的。

CAS本身是CPU的指令,操作系統對其做了封裝,jvm又對操作系統提供的api又做了一層封裝。java中CAS的api是放在unsafe中的,這個包名的意思,顧名思義也是“不安全”的意思,一般在java中不建議使用,java的標準庫中,對于CAS進行了進一步的封裝,把CAS的一些操作封裝成工具類,供程序猿使用。而主要的一個工具,叫做 “原子類”。

java.util.concurrent.atomic? 包下,里面的類就是基于上述方式實現的,典型的類就是AtomicInteger類,里面有很多方法可以實現數值的自增、自減,以及基本的加減操作。下面的代碼案例也是使用AtomicInteger展示。

我們以前寫過一個代碼,讓兩個線程實現一個變量自增10_0000次,如下代碼是線程不安全。

public class AtomicIntegerTest1 {public static int count = 0;public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> {for (int i = 0; i < 50000; i++) {count++;}});Thread t2 = new Thread(() -> {for (int i = 0; i < 50000; i++) {count++;}});t1.start();t2.start();t1.join();t2.join();System.out.println(count);}
}

執行結果:

輸出結果也和我們預期結果不同,肯定是線程不安全的,而原因就是因為count++操作不是原子的,在計算機中有三個指令

這里,我們使用CAS的方式,來實現讓兩個線程實現一個變量自增10_0000次,代碼如下

public class AtomicIntegerTest1 {public static AtomicInteger count = new AtomicInteger(0);public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> {for (int i = 0; i < 50000; i++) {count.getAndIncrement();//和count++意思一樣}});Thread t2 = new Thread(() -> {for (int i = 0; i < 50000; i++) {count.getAndIncrement();//和count++意思一樣}});t1.start();t2.start();t1.join();t2.join();System.out.println(count);}
}

執行結果:

因為這里用CAS的方式,原本count++操作在計算機中有3條指令,不是原子的,肯定線程不安全;但是用CAS的方式就可以把像count++這樣的操作,用一條指令完成,是原子的,在這里就不涉及到線程安全問題了。

AtomicInteger中有很多方法:自增,自減,+=,-=等待,這里就不展開討論了。


三、原子類自增的代碼分析

代碼還是上述的代碼,如下:

public class AtomicIntegerTest1 {public static AtomicInteger count = new AtomicInteger(0);public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> {for (int i = 0; i < 50000; i++) {count.getAndIncrement();//和count++意思一樣}});Thread t2 = new Thread(() -> {for (int i = 0; i < 50000; i++) {count.getAndIncrement();//和count++意思一樣}});t1.start();t2.start();t1.join();t2.join();System.out.println(count);}
}

在標準庫中,getAndIncrement方法是這樣的:

這里比較難理解,我們用偽代碼的形式介紹,偽代碼如下:

當有兩個線程對同一個變量進行自增操作時,執行流程是這樣的:

這里的oldValue是寄存器中的值,它的值就是AtomicInteger括號里面初始化的值,value是內存中的值。從上到下,把內存value的值都賦值給oldValue,兩個線程拿到的都是同一個內存value的值。

這時,右邊的線程while循環里的判斷,先執行CAS這里的操作,如圖:

????????

執行完CAS操作后返回true,然后while循環里true != ture,條件不成立,不執行while循環內的代碼。

當左邊線程進入while循環里面的判斷語句時,如圖:

也會進入CAS操作,這里因為內存value的值修改了,當前線程寄存器oldValue值還是0,給oldValue+1,會返回false,這時循環條件false != true成立,就會執行oldValue = value操作,如圖:

再次進入循環條件里面執行CAS操作,這時候value == oldValue,所以會讓oldvalue+1賦值給value,這時候value的值就是2了,如圖:

所以,兩個線程不管順序是啥樣的,使用getAndIncrement方法都不會出現線程安全問題,因為CAS操作本身就是原子的,原因的邏輯理解也大概是下面這樣的:

如果cas不成功,會重復上面的操作,再次讀取數據,這次讀取到的數據就是正確的了,cas也就能成功。意思就是這個方法里面會判斷拿到的值是不是最新值,如果不是就去拿最新的值,再去CAS,這時候因為拿到的是最新值,所以這時能CAS成功。


都看到這了,點個贊再走吧,謝謝謝謝謝

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/211311.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/211311.shtml
英文地址,請注明出處:http://en.pswp.cn/news/211311.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

C語言——字符函數和字符串函數(一)

&#x1f4dd;前言&#xff1a; 這篇文章對我最近學習的有關字符串的函數做一個總結和整理&#xff0c;主要講解字符函數和字符串函數&#xff08;strlen&#xff0c;strcpy和strncpy&#xff0c;strcat和strncat&#xff09;的使用方法&#xff0c;使用場景和一些注意事項&…

python常見庫的匯總

python常見庫 一、爬蟲二、界面開發三、圖片處理四、視頻處理、視頻剪輯五、音頻處理六、數據處理七、數據庫八、網頁開發九、神經學習、AI開發十、打包十一、Excel處理十二、微信十三、控制鼠標鍵盤十四、手柄十五、控制外設十六、郵箱十七、短信 一、爬蟲 Requests&#xff…

Java入門項目--螞蟻愛購

簡介 這是一個靠譜的Java入門項目實戰&#xff0c;名字叫螞蟻愛購。 從零開發項目&#xff0c;視頻加文檔&#xff0c;十天就能學會開發JavaWeb項目&#xff0c;教程路線是&#xff1a;搭建環境> 安裝軟件> 創建項目> 添加依賴和配置> 通過表生成代碼> 編寫Ja…

解鎖MySQL的威力:針對常見問題的快速解決指南

數據庫和表的創建 創建數據庫&#xff1a; CREATE DATABASE IF NOT EXISTS MyDatabase; USE MyDatabase;案例&#xff1a; 想象您要開始一個博客項目。首先&#xff0c;您需要一個地方來存儲所有的文章和用戶信息。上述命令幫助您創建了這樣一個存儲空間&#xff0c;名為MyDa…

Tomcat使用https方式連接

Tomcat使用https方式連接 攏共分兩步&#xff0c;第一步&#xff1a;生成密鑰。第二步&#xff1a;修改配置。 第一步&#xff1a;生成密鑰。 keytool -genkey -v -alias tomcat -keyalg RSA -validity 365 -keystore /usr/tomcat-8.5/conf/tomcat.keystore第二步&#xff1…

RocketMQ-源碼架構二

梳理一些比較完整&#xff0c;比較復雜的業務線 消息持久化設計 RocketMQ的持久化文件結構 消息持久化也就是將內存中的消息寫入到本地磁盤的過程。而磁盤IO操作通常是一個很耗性能&#xff0c;很慢的操作&#xff0c;所以&#xff0c;對消息持久化機制的設計&#xff0c;是…

華為機試真題 C++ 實現【字符串重新排列】

題目 給定一個字符串s&#xff0c;s包括以空格分隔的若干個單詞&#xff0c;請對s進行如下處理后輸出&#xff1a; 1、單詞內部調整&#xff1a;對每個單詞字母重新按字典序排序 2、單詞間順序調整&#xff1a; 1&#xff09;統計每個單詞出現的次數&#xff0c;并按次數降序…

蒙特霍爾問題(選擇三扇門后的車與羊)及其貝葉斯定理數學解釋

1. 蒙特霍爾問題 有一個美國電視游戲節目叫做“Let’s Make a Deal”&#xff0c;游戲中參賽者將面對3扇關閉的門&#xff0c;其中一扇門背后有一輛汽車&#xff0c;另外兩扇門后是山羊&#xff0c;參賽者如果能猜中哪一扇門后是汽車&#xff0c;就可以得到它。 通常&#xf…

筆記68:Pytorch中repeat函數的用法

repeat 相當于一個broadcasting的機制 repeat(*sizes) 沿著指定的維度重復tensor。不同與expand()&#xff0c;本函數復制的是tensor中的數據。 import torch import torch.nn.functional as F import numpy as np a torch.Tensor(128,1,512) B a.repeat(1,5,1) print(B.s…

OpenGL 著色器程序的保存和加載(二進制)

背景 為了提高OpenGL 著色器程序的編譯和鏈接速度&#xff0c;我們可以將程序保存為二進制進行加載&#xff0c;可以大幅度提升加載效率。 方法 以下是加載和保存二進制程序的方法。 // 加載著色器程序的二進制文件到已創建的著色器程序中 bool loadPragram(const std::str…

javaee實驗:文件上傳及攔截器的使用

目錄 文件上傳ModelAttribute注解實驗目的實驗內容實驗過程項目結構編寫代碼結果展示 文件上傳 Spring MVC 提供 MultipartFile 接口作為參數來處理文件上傳。 MultipartFile 提供以下方法來獲取上傳的文件信息&#xff1a; ? getOriginalFilename 獲取上傳的文件名字&#x…

華為OD機試真題-測試用例執行計劃-2023年OD統一考試(C卷)

題目描述: 某個產品當前迭代周期內有N個特性( F1,F2,.......FN)需要進行覆蓋測試,每個特性都被評估了對應的優先級,特性使用其ID作為下標進行標識。 設計了M個測試用例(T1,T2......,TM ),每個用例對應了一個覆蓋特性的集合,測試用例使用其ID作為下標進行標識,測試用例…

特權FPGA學習筆記

C/C/system C-----vivado HLS------------->RTL門電路&#xff0c;省去了HDL語言的中間轉換&#xff0c;可以看作是C向C#的演進&#xff0c;基于zynq面向以前使用C的開發人員&#xff0c;但是個人覺得&#xff0c;HDL存在且未被C取代&#xff0c;工具的著眼點就是面向底層調…

Spring Cloud 與微服務學習總結(19)—— Spring Cloud Alibaba 之 Nacos 2.3.0 史上最大更新版本發布

Nacos 一個用于構建云原生應用的動態服務發現、配置管理和服務管理平臺,由阿里巴巴開源,致力于發現、配置和管理微服務。說白了,Nacos 就是充當微服務中的的注冊中心和配置中心。 Nacos 2.3.0 新特性 1. 反脆弱插件 Nacos 2.2.0 版本開始加入反脆弱插件,從 2.3.0 版本開…

飛天使-linux操作的一些技巧與知識點2

TCP 的三次握手 第一次&#xff0c;客戶端與服務端建立鏈接&#xff0c;需要發送請求連接的消息 第二次&#xff0c;服務端接口到數據后&#xff0c;返回一個確認的操作*&#xff08;至此客戶端和服務端鏈路建立成功&#xff09; 第三次&#xff0c;服務端還需要發送要與客戶端…

【Linux】探索Linux進程狀態 | 僵尸進程 | 孤兒進程

最近&#xff0c;我發現了一個超級強大的人工智能學習網站。它以通俗易懂的方式呈現復雜的概念&#xff0c;而且內容風趣幽默。我覺得它對大家可能會有所幫助&#xff0c;所以我在此分享。點擊這里跳轉到網站。 目錄 一、進程狀態1.1運行狀態1.2阻塞狀態1.3掛起狀態 二、具體L…

React中使用react-json-view展示JSON數據

文章目錄 一、前言1.1、在線demo1.2、Github倉庫 二、實踐2.1、安裝react-json-view2.2、組件封裝2.3、效果2.4、參數詳解2.4.1、src(必須) &#xff1a;JSON Object2.4.2、name&#xff1a;string或false2.4.3、theme&#xff1a;string2.4.4、style&#xff1a;object2.4.5、…

[ROS2] --- service

1 service介紹 1.1 service概念 話題通信是基于訂閱/發布機制的&#xff0c;無論有沒有訂閱者&#xff0c;發布者都會周期發布數據&#xff0c;這種模式適合持續數據的收發&#xff0c;比如傳感器數據。機器人系統中還有另外一些配置性質的數據&#xff0c;并不需要周期處理&…

C#,圖算法——以鄰接節點表示的圖最短路徑的迪杰斯特拉(Dijkstra)算法C#程序

1 文本格式 using System; using System.Text; using System.Linq; using System.Collections; using System.Collections.Generic; namespace Legalsoft.Truffer.Algorithm { public class Node // : IComparable<Node> { private int vertex, weigh…

第7章-使用統計方法進行變量有效性測試-7.5.4-模型評估

目錄 混淆矩陣 準確率 定義 局限性 精準率 定義 局限性