本篇內(nèi)容主要講解“并發(fā)編程三要素是什么”,感興趣的朋友不妨來看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“并發(fā)編程三要素是什么”吧!
十年的長(zhǎng)安網(wǎng)站建設(shè)經(jīng)驗(yàn),針對(duì)設(shè)計(jì)、前端、開發(fā)、售后、文案、推廣等六對(duì)一服務(wù),響應(yīng)快,48小時(shí)及時(shí)工作處理。成都營(yíng)銷網(wǎng)站建設(shè)的優(yōu)勢(shì)是能夠根據(jù)用戶設(shè)備顯示端的尺寸不同,自動(dòng)調(diào)整長(zhǎng)安建站的顯示方式,使網(wǎng)站能夠適用不同顯示終端,在瀏覽器中調(diào)整網(wǎng)站的寬度,無論在任何一種瀏覽器上瀏覽網(wǎng)站,都能展現(xiàn)優(yōu)雅布局與設(shè)計(jì),從而大程度地提升瀏覽體驗(yàn)。創(chuàng)新互聯(lián)建站從事“長(zhǎng)安網(wǎng)站設(shè)計(jì)”,“長(zhǎng)安網(wǎng)站推廣”以來,每個(gè)客戶項(xiàng)目都認(rèn)真落實(shí)執(zhí)行。
**原子性:**一個(gè)不可再被分割的顆粒。原子性指的是一個(gè)或多個(gè)操作要么全部執(zhí)行成功要么全部執(zhí)行失敗。
有序性:程序執(zhí)行的順序按照代碼的先后順序執(zhí)行。(處理器可能會(huì)對(duì)指令進(jìn)行重排序)
可見性:一個(gè)縣城對(duì)共享變量的修改,另一個(gè)線程能夠立刻看到。
線程切換會(huì)帶來原子性的問題
int i = 1; // 原子操作 i++; // 非原子操作,從主內(nèi)存讀取 i 到線程工作內(nèi)存,進(jìn)行 +1,再把 i 寫到主內(nèi)存。
雖然讀取和寫入都是原子操作,但合起來就不屬于原子操作,我們又叫這種為“復(fù)合操作”。
我們可以用synchronized 或 Lock 來把這個(gè)復(fù)合操作“變成”原子操作。
例子:
//使用synchronized private synchronized void increase(){ i++; } //使用Lock private int i = 0; Lock mLock = new ReentrantLock(); private void increase() { mLock.lock(); try { i++; } finally{ mLock.unlock(); } }
這樣我們就可以把這個(gè)一個(gè)方法看做一個(gè)整體,一個(gè)不可分割的整體。
除此之前,我們還可以用java.util.concurrent.atomic里的原子變量類,可以確保所有對(duì)計(jì)數(shù)器狀態(tài)訪問的操作都是原子的。
例子:
AtomicInteger mAtomicInteger = new AtomicInteger(0); private void increase(){ mAtomicInteger.incrementAndGet(); }
緩存導(dǎo)致可見性問題
int v = 0; // 線程 A 執(zhí)行 v++; // 線程 B 執(zhí)行 System.out.print("v=" + v);
即使是在執(zhí)行完線程里的 i++ 后再執(zhí)行線程 B,線程 B 的輸入結(jié)果也會(huì)有 2 個(gè)種情況,一個(gè)是 0 和1。
因?yàn)?i++ 在線程 A(CPU-1)中做完了運(yùn)算,并沒有立刻更新到主內(nèi)存當(dāng)中,而線程B(CPU-2)就去主內(nèi)存當(dāng)中讀取并打印,此時(shí)打印的就是 0。
禁用緩存能保證可見性,volatile關(guān)鍵字可以禁用緩存
synchronized和Lock能夠保證可見性。
導(dǎo)致有序性的原因是編譯優(yōu)化
我們都知道處理器為了擁有更好的運(yùn)算效率,會(huì)自動(dòng)優(yōu)化、排序執(zhí)行我們寫的代碼,但會(huì)確保執(zhí)行結(jié)果不變。
例子:
int a = 0; // 語句 1 int b = 0; // 語句 2 i++; // 語句 3 b++; // 語句 4
這一段代碼的執(zhí)行順序很有可能不是按上面的 1、2、3、4 來依次執(zhí)行,因?yàn)?1 和 2 沒有數(shù)據(jù)依賴,3 和 4 沒有數(shù)據(jù)依賴, 2、1、4、3 這樣來執(zhí)行可以嗎?完全沒問題,處理器會(huì)自動(dòng)幫我們排序。
在單線程看來并沒有什么問題,但在多線程則很容易出現(xiàn)問題。
再來個(gè)例子:
// 線程 1 init(); inited = true; // 線程 2 while(inited){ work(); }
init(); 與 inited = true; 并沒有數(shù)據(jù)的依賴,在單線程看來,如果把兩句的代碼調(diào)換好像也不會(huì)出現(xiàn)問題。
但此時(shí)處于一個(gè)多線程的環(huán)境,而處理器真的把這兩句代碼重新排序,那問題就出現(xiàn)了,若線程 1 先執(zhí)行 inited = true; 此時(shí),init() 并沒有執(zhí)行,線程 2 就已經(jīng)開始調(diào)用 work() 方法,此時(shí)很可能造成一些奔潰或其他 BUG 的出現(xiàn)。
synchronized和Lock能確保原子性,能讓多線程執(zhí)行代碼的時(shí)候依次按順序執(zhí)行,自然就具有有序性。
而volatile關(guān)鍵字也可以解決這個(gè)問題,volatile 關(guān)鍵字可以保證有序性,讓處理器不會(huì)把這行代碼進(jìn)行優(yōu)化排序。
到此,相信大家對(duì)“并發(fā)編程三要素是什么”有了更深的了解,不妨來實(shí)際操作一番吧!這里是創(chuàng)新互聯(lián)網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!