1. 程式人生 > >第十一章 AtomicInteger原始碼解析

第十一章 AtomicInteger原始碼解析

1、原子類

  • 可以實現一些原子操作
  • 基於CAS

下面就以AtomicInteger為例。

2、AtomicInteger

在沒有AtomicInteger之前,對於一個Integer的執行緒安全操作,是需要使用同步鎖來實現的,當然現在也可以通過ReentrantLock來實現,但是最好最方便的實現方式是採用AtomicInteger。

具體示例:

package com.collection.test;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * 原子類的測試
 */
public
class 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(); } }
View Code

原始碼:

    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 (接口) 保存獨立