真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

Java多線程Atomic包操作原子變量與原子類的示例分析

這篇文章主要介紹Java多線程Atomic包操作原子變量與原子類的示例分析,文中介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們一定要看完!

專注于為中小企業(yè)提供成都做網(wǎng)站、成都網(wǎng)站設(shè)計(jì)服務(wù),電腦端+手機(jī)端+微信端的三站合一,更高效的管理,為中小企業(yè)榮成免費(fèi)做網(wǎng)站提供優(yōu)質(zhì)的服務(wù)。我們立足成都,凝聚了一批互聯(lián)網(wǎng)行業(yè)人才,有力地推動(dòng)了上千家企業(yè)的穩(wěn)健成長,幫助中小企業(yè)通過網(wǎng)站建設(shè)實(shí)現(xiàn)規(guī)模擴(kuò)充和轉(zhuǎn)變。

一、何謂Atomic?

Atomic一詞跟原子有點(diǎn)關(guān)系,后者曾被人認(rèn)為是最小物質(zhì)的單位。計(jì)算機(jī)中的Atomic是指不能分割成若干部分的意思。如果一段代碼被認(rèn)為是Atomic,則表示這段代碼在執(zhí)行過程中,是不能被中斷的。通常來說,原子指令由硬件提供,供軟件來實(shí)現(xiàn)原子方法(某個(gè)線程進(jìn)入該方法后,就不會(huì)被中斷,直到其執(zhí)行完成)

在x86平臺(tái)上,CPU提供了在指令執(zhí)行期間對(duì)總線加鎖的手段。CPU芯片上有一條引線#HLOCKpin,如果匯編語言的程序中在一條指令前面加上前綴"LOCK",經(jīng)過匯編以后的機(jī)器代碼就使CPU在執(zhí)行這條指令的時(shí)候把#HLOCKpin的電位拉低,持續(xù)到這條指令結(jié)束時(shí)放開,從而把總線鎖住,這樣同一總線上別的CPU就暫時(shí)不能通過總線訪問內(nèi)存了,保證了這條指令在多處理器環(huán)境中的原子性。

二、java.util.concurrent中的原子變量

無論是直接的還是間接的,幾乎java.util.concurrent包中的所有類都使用原子變量,而不使用同步。類似ConcurrentLinkedQueue的類也使用原子變量直接實(shí)現(xiàn)無等待算法,而類似ConcurrentHashMap的類使用ReentrantLock在需要時(shí)進(jìn)行鎖定。然后,ReentrantLock使用原子變量來維護(hù)等待鎖定的線程隊(duì)列。

如果沒有JDK5.0中的JVM改進(jìn),將無法構(gòu)造這些類,這些改進(jìn)暴露了(向類庫,而不是用戶類)接口來訪問硬件級(jí)的同步原語。然后,java.util.concurrent中的原子變量類和其他類向用戶類公開這些功能

java.util.concurrent.atomic的原子類

這個(gè)包里面提供了一組原子類。其基本的特性就是在多線程環(huán)境下,當(dāng)有多個(gè)線程同時(shí)執(zhí)行這些類的實(shí)例包含的方法時(shí),具有排他性,即當(dāng)某個(gè)線程進(jìn)入方法,執(zhí)行其中的指令時(shí),不會(huì)被其他線程打斷,而別的線程就像自旋鎖一樣,一直等到該方法執(zhí)行完成,才由JVM從等待隊(duì)列中選擇一個(gè)另一個(gè)線程進(jìn)入,這只是一種邏輯上的理解。實(shí)際上是借助硬件的相關(guān)指令來實(shí)現(xiàn)的,不會(huì)阻塞線程(或者說只是在硬件級(jí)別上阻塞了)。其中的類可以分成4組

AtomicBoolean,AtomicInteger,AtomicLong,AtomicReference 
AtomicIntegerArray,AtomicLongArray 
AtomicLongFieldUpdater,AtomicIntegerFieldUpdater,AtomicReferenceFieldUpdater 
AtomicMarkableReference,AtomicStampedReference,AtomicReferenceArray 

其中AtomicBoolean,AtomicInteger,AtomicLong,AtomicReference是類似的。

首先AtomicBoolean,AtomicInteger,AtomicLong,AtomicReference內(nèi)部api是類似的:舉個(gè)AtomicReference的例子

使用AtomicReference創(chuàng)建線程安全的堆棧

public class LinkedStack {
	private AtomicReference> stacks = new AtomicReference>();
	public T push(T e) {
		Node oldNode, newNode;
		while (true) {
			//這里的處理非常的特別,也是必須如此的。 
			oldNode = stacks.get();
			newNode = new Node(e, oldNode);
			if (stacks.compareAndSet(oldNode, newNode)) {
				return e;
			}
		}
	}
	public T pop() {
		Node oldNode, newNode;
		while (true) {
			oldNode = stacks.get();
			newNode = oldNode.next;
			if (stacks.compareAndSet(oldNode, newNode)) {
				return oldNode.object;
			}
		}
	}
	private static final class Node {
		private T object;
		private Node next;
		private Node(T object, Node next) {
			this.object = object;
			this.next = next;
		}
	}
}

然后關(guān)注字段的原子更新。

AtomicIntegerFieldUpdater/AtomicLongFieldUpdater/AtomicReferenceFieldUpdater是基于反射的原子更新字段的值。

相應(yīng)的API也是非常簡單的,但是也是有一些約束的。

(1)字段必須是volatile類型的!volatile到底是個(gè)什么東西。請(qǐng)查看《Java中Volatile關(guān)鍵字詳解》

(2)字段的描述類型(修飾符public/protected/default/private)是與調(diào)用者與操作對(duì)象字段的關(guān)系一致。也就是說調(diào)用者能夠直接操作對(duì)象字段,那么就可以反射進(jìn)行原子操作。但是對(duì)于父類的字段,子類是不能直接操作的,盡管子類可以訪問父類的字段。

(3)只能是實(shí)例變量,不能是類變量,也就是說不能加static關(guān)鍵字。

(4)只能是可修改變量,不能使final變量,因?yàn)閒inal的語義就是不可修改。實(shí)際上final的語義和volatile是有沖突的,這兩個(gè)關(guān)鍵字不能同時(shí)存在。

(5)對(duì)于AtomicIntegerFieldUpdater和AtomicLongFieldUpdater只能修改int/long類型的字段,不能修改其包裝類型(Integer/Long)。如果要修改包裝類型就需要使用AtomicReferenceFieldUpdater。

在下面的例子中描述了操作的方法。

import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
public class AtomicIntegerFieldUpdaterDemo {
	class DemoData{
		public volatile int value1 = 1;
		volatile int value2 = 2;
		protected volatile int value3 = 3;
		private volatile int value4 = 4;
	}
	AtomicIntegerFieldUpdater getUpdater(String fieldName) {
		return AtomicIntegerFieldUpdater.newUpdater(DemoData.class, fieldName);
	}
	void doit() {
		DemoData data = new DemoData();
		System.out.println("1 ==> "+getUpdater("value1").getAndSet(data, 10));
		System.out.println("3 ==> "+getUpdater("value2").incrementAndGet(data));
		System.out.println("2 ==> "+getUpdater("value3").decrementAndGet(data));
		System.out.println("true ==> "+getUpdater("value4").compareAndSet(data, 4, 5));
	}
	public static void main(String[] args) {
		AtomicIntegerFieldUpdaterDemo demo = new AtomicIntegerFieldUpdaterDemo();
		demo.doit();
	}
}

在上面的例子中DemoData的字段value3/value4對(duì)于AtomicIntegerFieldUpdaterDemo類是不可見的,因此通過反射是不能直接修改其值的。

AtomicMarkableReference類描述的一個(gè)的對(duì),可以原子的修改Object或者Boolean的值,這種數(shù)據(jù)結(jié)構(gòu)在一些緩存或者狀態(tài)描述中比較有用。這種結(jié)構(gòu)在單個(gè)或者同時(shí)修改Object/Boolean的時(shí)候能夠有效的提高吞吐量。

AtomicStampedReference類維護(hù)帶有整數(shù)“標(biāo)志”的對(duì)象引用,可以用原子方式對(duì)其進(jìn)行更新。對(duì)比AtomicMarkableReference類的,AtomicStampedReference維護(hù)的是一種類似的數(shù)據(jù)結(jié)構(gòu),其實(shí)就是對(duì)對(duì)象(引用)的一個(gè)并發(fā)計(jì)數(shù)。但是與AtomicInteger不同的是,此數(shù)據(jù)結(jié)構(gòu)可以攜帶一個(gè)對(duì)象引用(Object),并且能夠?qū)Υ藢?duì)象和計(jì)數(shù)同時(shí)進(jìn)行原子操作。

在本文結(jié)尾會(huì)提到“ABA問題”,而AtomicMarkableReference/AtomicStampedReference在解決“ABA問題”上很有用。

三、Atomic類的作用

使得讓對(duì)單一數(shù)據(jù)的操作,實(shí)現(xiàn)了原子化

使用Atomic類構(gòu)建復(fù)雜的,無需阻塞的代碼

訪問對(duì)2個(gè)或2個(gè)以上的atomic變量(或者對(duì)單個(gè)atomic變量進(jìn)行2次或2次以上的操作)通常認(rèn)為是需要同步的,以達(dá)到讓這些操作能被作為一個(gè)原子單元。

無鎖定且無等待算法

基于CAS(compareandswap)的并發(fā)算法稱為無鎖定算法,因?yàn)榫€程不必再等待鎖定(有時(shí)稱為互斥或關(guān)鍵部分,這取決于線程平臺(tái)的術(shù)語)。無論CAS操作成功還是失敗,在任何一種情況中,它都在可預(yù)知的時(shí)間內(nèi)完成。如果CAS失敗,調(diào)用者可以重試CAS操作或采取其他適合的操作。

如果每個(gè)線程在其他線程任意延遲(或甚至失?。r(shí)都將持續(xù)進(jìn)行操作,就可以說該算法是無等待的。與此形成對(duì)比的是,無鎖定算法要求僅某個(gè)線程總是執(zhí)行操作。(無等待的另一種定義是保證每個(gè)線程在其有限的步驟中正確計(jì)算自己的操作,而不管其他線程的操作、計(jì)時(shí)、交叉或速度。這一限制可以是系統(tǒng)中線程數(shù)的函數(shù);例如,如果有10個(gè)線程,每個(gè)線程都執(zhí)行一次CasCounter.increment()操作,最壞的情況下,每個(gè)線程將必須重試最多九次,才能完成增加。)

再過去的15年里,人們已經(jīng)對(duì)無等待且無鎖定算法(也稱為無阻塞算法)進(jìn)行了大量研究,許多人通用數(shù)據(jù)結(jié)構(gòu)已經(jīng)發(fā)現(xiàn)了無阻塞算法。無阻塞算法被廣泛用于操作系統(tǒng)和JVM級(jí)別,進(jìn)行諸如線程和進(jìn)程調(diào)度等任務(wù)。雖然它們的實(shí)現(xiàn)比較復(fù)雜,但相對(duì)于基于鎖定的備選算法,它們有許多優(yōu)點(diǎn):可以避免優(yōu)先級(jí)倒置和死鎖等危險(xiǎn),競爭比較便宜,協(xié)調(diào)發(fā)生在更細(xì)的粒度級(jí)別,允許更高程度的并行機(jī)制等等。

常見的:

非阻塞的計(jì)數(shù)器Counter

非阻塞堆棧ConcurrentStack

非阻塞的鏈表ConcurrentLinkedQueue

ABA問題:

因?yàn)樵诟腣之前,CAS主要詢問“V的值是否仍為A”,所以在第一次讀取V以及對(duì)V執(zhí)行CAS操作之前,如果將值從A改為B,然后再改回A,會(huì)使基于CAS的算法混亂。在這種情況下,CAS操作會(huì)成功,但是在一些情況下,結(jié)果可能不是您所預(yù)期的。這類問題稱為ABA問題,通常通過將標(biāo)記或版本編號(hào)與要進(jìn)行CAS操作的每個(gè)值相關(guān)聯(lián),并原子地更新值和標(biāo)記,來處理這類問題。AtomicStampedReference類支持這種方法。

以上是“Java多線程Atomic包操作原子變量與原子類的示例分析”這篇文章的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對(duì)大家有幫助,更多相關(guān)知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道!


標(biāo)題名稱:Java多線程Atomic包操作原子變量與原子類的示例分析
標(biāo)題網(wǎng)址:http://weahome.cn/article/igdsed.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部