第十一章 AtomicInteger原始碼解析
1、原子類
- 可以實現一些原子操作
- 基於CAS
下面就以AtomicInteger為例。
2、AtomicInteger
在沒有AtomicInteger之前,對於一個Integer的執行緒安全操作,是需要使用同步鎖來實現的,當然現在也可以通過ReentrantLock來實現,但是最好最方便的實現方式是採用AtomicInteger。
具體示例:
package com.collection.test; import java.util.concurrent.atomic.AtomicInteger; /** * 原子類的測試 */ publicView Codeclass AtomicTest { private static AtomicInteger atomicInteger = new AtomicInteger(); //獲取當前值 public static void getCurrentValue(){ System.out.println(atomicInteger.get());//-->0 } //設定value值 public static void setValue(){ atomicInteger.set(12);//直接用12覆蓋舊值 System.out.println(atomicInteger.get());//-->12 } //根據方法名稱getAndSet就知道先get,則最後返回的就是舊值,如果get在後,就是返回新值 public static void getAndSet(){ System.out.println(atomicInteger.getAndSet(15));//-->12 } public static void getAndIncrement(){ System.out.println(atomicInteger.getAndIncrement());//-->15 } public static void getAndDecrement(){ System.out.println(atomicInteger.getAndDecrement());//-->16 } public static void getAndAdd(){ System.out.println(atomicInteger.getAndAdd(10));//-->15 } public static void incrementAndGet(){ System.out.println(atomicInteger.incrementAndGet());//-->26 } public static void decrementAndGet(){ System.out.println(atomicInteger.decrementAndGet());//-->25 } public static void addAndGet(){ System.out.println(atomicInteger.addAndGet(20));//-->45 } public static void main(String[] args) { AtomicTest test = new AtomicTest(); test.getCurrentValue(); test.setValue(); //返回舊值系列 test.getAndSet(); test.getAndIncrement(); test.getAndDecrement(); test.getAndAdd(); //返回新值系列 test.incrementAndGet(); test.decrementAndGet(); test.addAndGet(); } }
原始碼:
private volatile int value;// 初始化值 /** * 建立一個AtomicInteger,初始值value為initialValue */ public AtomicInteger(int initialValue) { value = initialValue; } /** * 建立一個AtomicInteger,初始值value為0 */ public AtomicInteger() { } /** * 返回value */ public final int get() { return value; } /** * 為value設值(基於value),而其他操作是基於舊值<--get() */ public final void set(int newValue) { value = newValue; } public final boolean compareAndSet(int expect, int update) { return unsafe.compareAndSwapInt(this, valueOffset, expect, update); } /** * 基於CAS為舊值設定新值,採用無限迴圈,直到設定成功為止 * * @return 返回舊值 */ public final int getAndSet(int newValue) { for (;;) { int current = get();// 獲取當前值(舊值) if (compareAndSet(current, newValue))// CAS新值替代舊值 return current;// 返回舊值 } } /** * 當前值+1,採用無限迴圈,直到+1成功為止 * @return the previous value 返回舊值 */ public final int getAndIncrement() { for (;;) { int current = get();//獲取當前值 int next = current + 1;//當前值+1 if (compareAndSet(current, next))//基於CAS賦值 return current; } } /** * 當前值-1,採用無限迴圈,直到-1成功為止 * @return the previous value 返回舊值 */ public final int getAndDecrement() { for (;;) { int current = get(); int next = current - 1; if (compareAndSet(current, next)) return current; } } /** * 當前值+delta,採用無限迴圈,直到+delta成功為止 * @return the previous value 返回舊值 */ public final int getAndAdd(int delta) { for (;;) { int current = get(); int next = current + delta; if (compareAndSet(current, next)) return current; } } /** * 當前值+1, 採用無限迴圈,直到+1成功為止 * @return the updated value 返回新值 */ public final int incrementAndGet() { for (;;) { int current = get(); int next = current + 1; if (compareAndSet(current, next)) return next;//返回新值 } } /** * 當前值-1, 採用無限迴圈,直到-1成功為止 * @return the updated value 返回新值 */ public final int decrementAndGet() { for (;;) { int current = get(); int next = current - 1; if (compareAndSet(current, next)) return next;//返回新值 } } /** * 當前值+delta,採用無限迴圈,直到+delta成功為止 * @return the updated value 返回新值 */ public final int addAndGet(int delta) { for (;;) { int current = get(); int next = current + delta; if (compareAndSet(current, next)) return next;//返回新值 } } /** * 獲取當前值 */ public int intValue() { return get(); }View Code
說明:使用與原始碼都簡單到爆了!自己看看註釋。
注意:
- 單步操作:例如set()是直接對value進行操作的,不需要CAS,因為單步操作就是原子操作。
- 多步操作:例如getAndSet(int newValue)是兩步操作-->先獲取值,在設定值,所以需要原子化,這裡採用CAS實現。
- 對於方法是返回舊值還是新值,直接看方法是以get開頭(返回舊值)還是get結尾(返回新值)就好
- CAS:比較CPU記憶體上的值是不是當前值current,如果是就換成新值update,如果不是,說明獲取值之後到設定值之前,該值已經被別人先一步設定過了,此時如果自己再設定值的話,需要在別人修改後的值的基礎上去操作,否則就會覆蓋別人的修改,所以這個時候會直接返回false,再進行無限迴圈,重新獲取當前值,然後再基於CAS進行加減操作。
- 如果還是不懂CAS,類比資料庫的樂觀鎖。
補充一個東西:
1 // setup to use Unsafe.compareAndSwapInt for updates 2 private static final Unsafe unsafe = Unsafe.getUnsafe(); 3 private static final long valueOffset; 4 5 static { 6 try { 7 valueOffset = unsafe.objectFieldOffset 8 (AtomicInteger.class.getDeclaredField("value")); 9 } catch (Exception ex) { throw new Error(ex); } 10 } 11 12 private volatile int value;
這是AtomicInteger的所有屬性,其中value存的是當前值,而當前值存放的記憶體地址可以通過valueOffset來確定。實際上是“value欄位相對Java物件的起始地址的偏移量”
1 public final boolean compareAndSet(int expect, int update) { 2 return unsafe.compareAndSwapInt(this, valueOffset, expect, update); 3 }
CAS方法:通過對比“valueOffset上的value”與expect是否相同,來決定是否修改value值為update值。
相關推薦
第十一章 AtomicInteger原始碼解析
1、原子類 可以實現一些原子操作 基於CAS 下面就以AtomicInteger為例。 2、AtomicInteger 在沒有AtomicInteger之前,對於一個Integer的執行緒安全操作,是需要使用同步鎖來實現的,當然現在也可以通過ReentrantLock來實現,但是最好最方
Scala學習整理[第三十一章 連線符解析]
第三十一章 連線符解析(Parser工具) package SecondWithProgrammingInScala import scala.util.parsing.combinator.{JavaTokenParsers, RegexParsers
第十一章 網絡文件共享服務之samba
windows 計算機 免費軟件 信息服務 全世界 Samba是在Linux和UNIX系統上實現SMB協議的一個免費軟件,由服務器及客戶端程序構成。在此之前我們已經了解了NFS和FTP,NFS與samba一樣,也是在網絡中實現文件共享的一種實現,但不幸的是,其不支持windows平臺,而本
構建之法第十一章讀後感
思維導圖 我們 加減乘除 圖形 計算 每日 導圖 case 中間 本周進行了構建之法的第十一章軟件設計與實現的學習; 第十一章主要講了典型的開發流程,常見的分析和設計方法:ERD,DFD,UML,開發階段的一些管理方法:每日構建,小強地獄,構建大師; 分析和設計方法包括以文
我的學習之路_第十一章_字符流
之間 才會 fileutil output keys 返回 ont 讀取數據 一個 【字符流】 IO流的分類 ★字節流 操作的文件不是文本文件 字節輸入流: InputStream 抽象類 FileInputStream操作文件的字節輸入流 字節輸出流: OutputStr
第十一章:基本系統的配置工具
scrip ati 設置 down dns system show 一個 work 1、配置網絡 2、配置和發送文本到打印服務(用的少,大家忘了他吧) 3、設置系統日期和時間 4、調度計劃任務 TCP/IP Network Configuration 配置IP地址
第十一章 springboot + mongodb(簡單查詢)
req all bool pan 可能 set 如果 創建 使用 1、mongodb在mac上的安裝 下載mongodb,https://www.mongodb.org/ 解壓縮到一個指定文件夾,如:/Users/enniu1/Desktop/zjg/mongodb
[學習筆記—Objective-C]《Objective-C-基礎教程 第2版》第十一章 屬性
變量名 erl .text nonatomic syn split view 不能 -name 11.1 使用屬性值 @property float rainHandling; //表明此類具有float類型的屬性,其名稱為rainHandling
構建基本腳本(第十一章)
基本腳本1.1 多命令; shell腳本可以通過;將命令串起來一起運行,甚至可以將前一個命令執行的結果作為參數傳給後一個命令執行。[[email protected]/* */ ~]# date;who Mon Jul 17 20:46:33 CST 2017 (unknown) :0
第十一章
oid sta next ted 命名 args dmi visit a* (1) 1.萬物皆對象:(地球上有什麽?我們會不自覺的將地球上的事物歸為具體類別) 2.對象:顧客 , 收銀員; 官方定義:用來描述客觀事,由一組屬
快學Scala習題解答—第十一章 操作符
+= reac gin 運行 eric 兩種 實例 大小 span 11 操作符 11.1 依據優先級規則,3 + 4 -> 5和3 -> 4 + 5是怎樣被求值的? 在REPL中運行就可以得到結果。都是從左至右運行
Oracle11g溫習-第十一章:管理undo
undo 大小 not table set lsp 星期 查看 reat 2013年4月27日 星期六 10:40 1、undo tablespace 功能 undo tablespace 功能:用來存放從datafiles 讀出的數據塊舊的鏡像
讀書筆記--《Python基礎教程第二版》--第十一章 文件和素材
ja第十一章 文件和素材11.1 打開文件 open函數用來打開文件,語法如下: open(name[,mode[,buffering]]) f = open(r‘/home/python/somefile.txt‘)11.1.1 文件模式r 讀模式w 寫模式a 追加模式b 二進制模式(可添加到其他的模式
JAVA-初步認識-第十一章-object類-equals方法
行修改 color 我們 兩個 例子 初步 是我 地方法 成了 一. 接下來介紹一個特殊的對象,學完繼承,多態,將要講到的,之前也接觸過。 之前談論的繼承體系子父類中,一直存在super()調用父類,父類中也有一個super()調用object。現在就是討論object對
第十一章習題答案
linux第十一章練習題答案?1. 如何把 /etc/passwd 中用戶uid 大於500 的行給打印出來?awk -f ‘:‘ ‘$3 > 500‘ /etc/passwd?2. awk中 nr,nf兩個變量表示什麽含義awk -f ‘:‘ ‘{print $nr}‘ /etc/passwd 會打印
深入理解計算機系統_3e 第十一章家庭作業 CS:APP3e chapter 11 homework
cep serve 技術分享 apn only class control 相同 法則 註:tiny.c csapp.c csapp.h等示例代碼均可在Code Examples獲取 11.6 A. 書上寫的示例代碼已經完成了大部分工作:doit函數中的printf("%
第十一章 關聯容器
count ace 關聯 mic mil const ret sin .com 使用關聯容器 使用set 1 #include<iostream> 2 #include<string> 3 #include<map> 4 5
Python編程:從入門到實踐——【作業】——第十一章(測試代碼)
stc 增加 收集 得到 width .com ast 接受 ted 第十一章 11-1 城市和國家 : 編寫一個函數, 它接受兩個形參: 一個城市名和一個國家名。 這個函數返回一個格式為City, Country 的字符串, 如Santiago, Chile 。 將這個函
第十一章 命令傳參過濾器、命令組合工具:xargs命令
shell命令傳參過濾器 shell命令組合工具 shell xargs命令 第十一章 命令傳參過濾器、命令組合工具:xargs命令 名詞解釋 xargs命令 是給其他命令傳遞參數的一個過濾器,也是組合多個命令的一個工具。它擅長將標準輸入數據轉換成命令行參數,xargs能夠處理管道或者stdin並
《Java編程思想》筆記 第十一章 持有對象
而且 位置 pty dex 優先級 poll IT ise 註意 1.保存對象引用 1.數組,數組具有固定大小 2.容器類,可自動調節大小 2.容器類 List Set Queue Map 及常用的實現類 2.1 Collectioon (接口) 保存獨立