這期內(nèi)容當(dāng)中小編將會(huì)給大家?guī)?lái)有關(guān)Java項(xiàng)目中實(shí)現(xiàn)多線(xiàn)程并發(fā)編程的條件有哪些,文章內(nèi)容豐富且以專(zhuān)業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。
伊犁網(wǎng)站建設(shè)公司創(chuàng)新互聯(lián)建站,伊犁網(wǎng)站設(shè)計(jì)制作,有大型網(wǎng)站制作公司豐富經(jīng)驗(yàn)。已為伊犁1000多家提供企業(yè)網(wǎng)站建設(shè)服務(wù)。企業(yè)網(wǎng)站搭建\成都外貿(mào)網(wǎng)站建設(shè)公司要多少錢(qián),請(qǐng)找那個(gè)售后服務(wù)好的伊犁做網(wǎng)站的公司定做!
一、原子性
原子,一個(gè)不可再被分割的顆粒。原子性,指的是一個(gè)或多個(gè)不能再被分割的操作。
int i = 1; // 原子操作
i++; // 非原子操作,從主內(nèi)存讀取 i 到線(xiàn)程工作內(nèi)存,進(jìn)行 +1,再把 i 寫(xiě)到朱內(nèi)存。
雖然讀取和寫(xiě)入都是原子操作,但合起來(lái)就不屬于原子操作,我們又叫這種為“復(fù)合操作”。
我們可以用synchronized 或 Lock 來(lái)把這個(gè)復(fù)合操作“變成”原子操作。
例子:
private synchronized void increase(){ i++; }
或
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里的原子變量類(lèi),可以確保所有對(duì)計(jì)數(shù)器狀態(tài)訪問(wèn)的操作都是原子的。
例子:
AtomicInteger mAtomicInteger = new AtomicInteger(0); private void increase(){ mAtomicInteger.incrementAndGet(); }
二、可見(jiàn)性
當(dāng)多線(xiàn)程訪問(wèn)某一個(gè)(同一個(gè))變量時(shí),其中一條線(xiàn)程對(duì)此變量作出修改,其他線(xiàn)程可以立刻讀取到最新修改后的變量。
int i = 0; // 線(xiàn)程 1 執(zhí)行 i++; // 線(xiàn)程 2 執(zhí)行 System.out.print("i=" + i);
即使是在執(zhí)行完線(xiàn)程里的 i++ 后再執(zhí)行線(xiàn)程 2,線(xiàn)程 2 的輸入結(jié)果也會(huì)有 2 個(gè)種情況,一個(gè)是 0 和 1。
因?yàn)?i++ 在線(xiàn)程 1(CPU1)中做完了運(yùn)算,并沒(méi)有立刻更新到主內(nèi)存當(dāng)中,而線(xiàn)程 2(CPU2)就去主內(nèi)存當(dāng)中讀取并打印,此時(shí)打印的就是 0。
synchronized和Lock能夠保證可見(jiàn)性。
另外volatile關(guān)鍵字也可以解決這個(gè)問(wèn)題(下一篇會(huì)講到)。
三、有序性
我們都知道處理器為了擁有更好的運(yùn)算效率,會(huì)自動(dòng)優(yōu)化、排序執(zhí)行我們寫(xiě)的代碼,但會(huì)確保執(zhí)行結(jié)果不變。
例子:
int a = 0; // 語(yǔ)句 1 int b = 0; // 語(yǔ)句 2 i++; // 語(yǔ)句 3 b++; // 語(yǔ)句 4
這一段代碼的執(zhí)行順序很有可能不是按上面的 1、2、3、4 來(lái)依次執(zhí)行,因?yàn)?1 和 2 沒(méi)有數(shù)據(jù)依賴(lài),3 和 4 沒(méi)有數(shù)據(jù)依賴(lài), 2、1、4、3 這樣來(lái)執(zhí)行可以嗎?完全沒(méi)問(wèn)題,處理器會(huì)自動(dòng)幫我們排序。
在單線(xiàn)程看來(lái)并沒(méi)有什么問(wèn)題,但在多線(xiàn)程則很容易出現(xiàn)問(wèn)題。
再來(lái)個(gè)例子:
// 線(xiàn)程 1 init(); inited = true; // 線(xiàn)程 2 while(inited){ work(); }
init(); 與 inited = true; 并沒(méi)有數(shù)據(jù)的依賴(lài),在單線(xiàn)程看來(lái),如果把兩句的代碼調(diào)換好像也不會(huì)出現(xiàn)問(wèn)題。
但此時(shí)處于一個(gè)多線(xiàn)程的環(huán)境,而處理器真的把這兩句代碼重新排序,那問(wèn)題就出現(xiàn)了,若線(xiàn)程 1 先執(zhí)行 inited = true; 此時(shí),init() 并沒(méi)有執(zhí)行,線(xiàn)程 2 就已經(jīng)開(kāi)始調(diào)用 work() 方法,此時(shí)很可能造成一些奔潰或其他 BUG 的出現(xiàn)。
synchronized和Lock能確保原子性,能讓多線(xiàn)程執(zhí)行代碼的時(shí)候依次按順序執(zhí)行,自然就具有有序性。
而volatile關(guān)鍵字也可以解決這個(gè)問(wèn)題,volatile 關(guān)鍵字可以保證有序性,讓處理器不會(huì)把這行代碼進(jìn)行優(yōu)化排序。
上述就是小編為大家分享的Java項(xiàng)目中實(shí)現(xiàn)多線(xiàn)程并發(fā)編程的條件有哪些了,如果剛好有類(lèi)似的疑惑,不妨參照上述分析進(jìn)行理解。如果想知道更多相關(guān)知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。