摘要:如果兩個(gè)線程存取相同的對象,并且每一個(gè)線程都調(diào)用一個(gè)修改該對象狀態(tài)的方法,根據(jù)線程訪問數(shù)據(jù)的順序,可能會出現(xiàn)錯(cuò)誤的數(shù)據(jù)結(jié)果,這種現(xiàn)象成為條件競爭。而問題往往就是有多個(gè)線程同時(shí)在執(zhí)行步驟。內(nèi)部鎖有如下的特點(diǎn)不能中斷正在試圖獲得鎖的線程。
【條件競爭
在多線程的開發(fā)中,兩個(gè)及其以上的線程需要共享統(tǒng)一數(shù)據(jù)的存取。如果兩個(gè)線程存取相同的對象,并且每一個(gè)線程都調(diào)用一個(gè)修改該對象狀態(tài)的方法,根據(jù)線程訪問數(shù)據(jù)的順序,可能會出現(xiàn)錯(cuò)誤的數(shù)據(jù)結(jié)果,這種現(xiàn)象成為條件競爭。因?yàn)樾薷膶ο鬆顟B(tài)的方法并不是一個(gè)原子操作,通常步驟是:
1. 讀取當(dāng)前狀態(tài)值到線程工作內(nèi)存。 2. 在線程工作內(nèi)存中修改狀態(tài)值。 3. 將修改后的狀態(tài)值重新寫入主內(nèi)存。
而問題往往就是有多個(gè)線程同時(shí)在執(zhí)行步驟2。
【 有兩種機(jī)制代碼受并發(fā)訪問的干擾synchronized關(guān)鍵字。
Reentrantlock類。
【synchronized關(guān)鍵字java中每個(gè)對象都有一個(gè)內(nèi)部鎖。如果一個(gè)方法是用synchronized關(guān)鍵字修聲明的,那么對象的鎖將保護(hù)整個(gè)方法,也就是說要調(diào)用該方法,線程必須獲得對象內(nèi)部鎖。內(nèi)部鎖有如下的特點(diǎn):
不能中斷正在試圖獲得鎖的線程。
試圖獲得鎖不能設(shè)置超時(shí)時(shí)間。
只有一個(gè)條件:要么獲得,要么等待,沒有粒度更細(xì)的控制。
【多個(gè)線程修改同一個(gè)對象造成數(shù)據(jù)失誤public class Sync { private int value; void add(){ this.value ++; } int getValue(){ return this.value; } public static void main(String[] args) { for (int i = 0; i <30 ; i++) { Sync s = new Sync(); Listcfs = new ArrayList<>(); cfs.add(CompletableFuture.runAsync(() -> s.add())); cfs.add(CompletableFuture.runAsync(() -> s.add())); cfs.add(CompletableFuture.runAsync(() -> s.add())); //等待子線程執(zhí)行完畢 CompletableFuture.allOf(cfs.toArray(new CompletableFuture[cfs.size()])).join(); System.out.println(s.getValue()); } } }
現(xiàn)在使用synchronized關(guān)鍵字修飾add()看看:數(shù)據(jù)正常。
【注意如果我們在同步的時(shí)候需要判斷,切記將條件判斷放在同步代碼塊之中,如果在外部判斷,很有可能出現(xiàn):
1. 第一個(gè)線程通過條件判斷 2. 第二個(gè)線程獲得cpu,并修改了共享對象 3. 第一個(gè)線程再次獲得cpu此時(shí)已經(jīng)不滿足條件,但是代碼在向下執(zhí)行,于是出現(xiàn)異常的情況。
例如轉(zhuǎn)賬的例子:
public class Account { //賬戶金額 private int amount; public Account(int amount){ this.amount = amount; } //轉(zhuǎn)賬 public synchronized void trans(Account to,int value){ //條件判斷處于同步代碼中?。。。。?! if(amount - value < 0){ throw new RuntimeException("錢不夠了!"); } this.amount -= value; to.addAmount(value); System.out.println("轉(zhuǎn)賬成功"); } public void addAmount(int amount){ this.amount += amount; } public int getAmount(){ return this.amount; } public static void main(String[] args) { Account from = new Account(100); Account to1 = new Account(0); Account to2 = new Account(0); Listcfs = new ArrayList<>(); cfs.add(CompletableFuture.runAsync(() -> from.trans(to1,100))); cfs.add(CompletableFuture.runAsync(() -> from.trans(to2,100))); CompletableFuture.allOf(cfs.toArray(new CompletableFuture[cfs.size()])).join(); System.out.println(from.getAmount()); System.out.println(to1.getAmount()); System.out.println(to2.getAmount()); } }
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/68094.html
摘要:假設(shè)不發(fā)生編譯器重排和指令重排,線程修改了的值,但是修改以后,的值可能還沒有寫回到主存中,那么線程得到就是很自然的事了。同理,線程對于的賦值操作也可能沒有及時(shí)刷新到主存中。線程的最后操作與線程發(fā)現(xiàn)線程已經(jīng)結(jié)束同步。 很久沒更新文章了,對隔三差五過來刷更新的讀者說聲抱歉。 關(guān)于 Java 并發(fā)也算是寫了好幾篇文章了,本文將介紹一些比較基礎(chǔ)的內(nèi)容,注意,閱讀本文需要一定的并發(fā)基礎(chǔ)。 本文的...
摘要:介紹中無鎖的線程安全整數(shù),一個(gè)提供原子操作的的類。在語言中,和操作并不是線程安全的,在使用的時(shí)候,不可避免的會用到關(guān)鍵字。而則通過一種線程安全的加減操作接口。就是的意思,比較并操作。有個(gè)操作數(shù),內(nèi)存值,舊的預(yù)期值,要修改的新值。 【介紹 JAVA 中無鎖的線程安全整數(shù) AtomicInteger,一個(gè)提供原子操作的Integer的類。在Java語言中,++i和i++操作并不是線程安全的...
摘要:死亡狀態(tài)線程退出有可能是正常執(zhí)行完成也有可能遇見異常退出。類有新建與死亡狀態(tài)返回其余狀態(tài)返回判斷線程是否存活。線程因某些原因進(jìn)入阻塞狀態(tài)。執(zhí)行同步代碼塊的過程中執(zhí)行了當(dāng)前線程放棄開始睡眠進(jìn)入就緒狀態(tài)但是不會釋放鎖。 【java內(nèi)存模型簡介 JVM中存在一個(gè)主存區(qū)(Main Memory或Java Heap Memory),Java中所有變量都是存在主存中的,對于所有線程進(jìn)行共享,而每個(gè)...
摘要:三關(guān)鍵字能保證原子性嗎并發(fā)編程藝術(shù)這本書上說保證但是在自增操作非原子操作上不保證,多線程編程核心藝術(shù)這本書說不保證。多線程訪問關(guān)鍵字不會發(fā)生阻塞,而關(guān)鍵字可能會發(fā)生阻塞關(guān)鍵字能保證數(shù)據(jù)的可見性,但不能保證數(shù)據(jù)的原子性。 系列文章傳送門: Java多線程學(xué)習(xí)(一)Java多線程入門 Java多線程學(xué)習(xí)(二)synchronized關(guān)鍵字(1) java多線程學(xué)習(xí)(二)synchroniz...
摘要:相比與其他操作系統(tǒng)包括其他類系統(tǒng)有很多的優(yōu)點(diǎn),其中有一項(xiàng)就是,其上下文切換和模式切換的時(shí)間消耗非常少。因?yàn)槎嗑€程競爭鎖時(shí)會引起上下文切換。減少線程的使用。很多編程語言中都有協(xié)程。所以如何避免死鎖的產(chǎn)生,在我們使用并發(fā)編程時(shí)至關(guān)重要。 系列文章傳送門: Java多線程學(xué)習(xí)(一)Java多線程入門 Java多線程學(xué)習(xí)(二)synchronized關(guān)鍵字(1) java多線程學(xué)習(xí)(二)syn...
閱讀 2158·2023-04-26 00:00
閱讀 3265·2021-09-24 10:37
閱讀 3534·2021-09-07 09:58
閱讀 1525·2019-08-30 15:56
閱讀 2223·2019-08-30 13:11
閱讀 2316·2019-08-29 16:38
閱讀 967·2019-08-29 12:58
閱讀 1884·2019-08-27 10:54