日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

学妹问我,并发问题的根源到底是什么?

發布時間:2025/3/16 编程问答 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 学妹问我,并发问题的根源到底是什么? 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

并發編程是 java 高級程序員的必備的基礎技能之一。但是想要寫好并發程序并非易事。

那究竟是什么原因導致大把的“格子衫”朋友無法寫出優質和性能穩定的并發程序呢?根本原因就是大家對并發編程的核心理論的模糊和不理解。想要運用好一項技術。理論知識和核心概念是一定要理解透徹的。

今天我們就來一起看下并發編程三大核心基礎理論:原子性、可見性、有序性

1、原子性

先來看下什么叫原子性

第一種理解:原子(atomic)本意是“不能被進一步分割的最小粒子”,而原子操作(atomic operation)意 為“不可被中斷的一個或一系列操作”

第二種理解:原子性,即一個操作或多個操作,要么全部執行并且在執行的過程中不被打斷,要么全部不執行。(提供了互斥訪問,在同一時刻只有一個線程進行訪問)

原子,在物理學中定義是組成物體的不可分割的最小的單位。在 java 并發編程中我們可以將其理解為:一組要么成功要么失敗的操作

1.1、原子性問題的產生的原因

原子性問題產生的根本原因是什么?我們只要知道了癥狀才能準確的對癥下藥,本小節,我們就來一起探討下原子性問題的由來。

我們都知道,程序在執行的時候,一定是以線程為單位在執行的,因為線程是 CPU 進行任務調度的基本單位

電腦的 CPU 會根據不同的任務調度算法去執行線程的調度,將時間分片并派分給各個線程。

當某個線程獲得CPU的時間片之后就獲取了CPU的執行權,就可以執行任務,當時間片耗盡之后,就會失去CPU使用權。

進而本任務會暫時的停止執行。多線程場景下,由于時間片在線程間輪換,就會發生原子性問題

看完理論似乎并不能直觀的理解原子性問題。下面我們就通過代碼的方式來具體闡述下原子性問題的產生原因。

1.2、案例分析

我們以常見的 i++ 為例,這是一個老生常談的原子性問題了,先來看下代碼

public class AtomicDemo {private int count = 0;public void add() {count++;}public int get() {return count;}public static void main(String[] args) throws InterruptedException {CountDownLatch countDownLatch = new CountDownLatch(100);AtomicDemo atomicDemo = new AtomicDemo();IntStream.rangeClosed(0, 100).forEach(item -> {new Thread(() -> {IntStream.rangeClosed(1, 100).forEach(i -> {atomicDemo.add();});}).start();countDownLatch.countDown();});countDownLatch.await();System.out.println(atomicDemo.get());} }

上面 代碼的作用是將初始值為0的 count 變量,通過100線程每個線程累加100次的方式來累加。想要得到一個結果為 10000 的值。但是實際上結果很難達到10000。

產生這個問題的原因:

count++ 的執行實際上這個操作不是原子性的,因為 count++ 會被拆分成以下三個步驟執行(這樣的步驟不是虛擬的,而是真實情況就是這么執行的)

第一步:讀取 count 的值;

第二步:計算 +1 的結果;

第三步:將 +1 的結果賦值給 count變量

那問題又來了。分三步又咋樣?讓他執行完不就行了?

理論上是這樣子的,大家都很友好,你執行完我執行,我執行完你繼續。你想象的可能是這樣的”烏托邦圖“

但是實際上這些線程已經”黑化”了。他們絕不可能互相謙讓。CPU或者是程序的世界觀里面。大家做任何事情都是在”爭搶“。我們來看下面這張圖:

上圖詳細分析:

第一步:A線程從主內存中讀取 count 的值 0;

第二步:A線程開始對 count 值進行累加;

第三步:B線程從主內存中讀取 count 的值 0(PS:具體第三步從哪里開始都不是重點,重點是:A線程將 count 值寫入主內存之前 B 線程就開始讀取 count 并執行此時 B線程 讀取到的 count 值依舊是還未被操作過的原始值);

第四步:(PS:到這里其實已經不重要了。因為不管 A線程和B線程現在怎么操作。結果已經不可逆轉,已經錯了)B線程開始對 count 值進行累加;

第五步:A 線程將累加后的結果賦值給 count 結果為 1;

第六步:B 線程將累加后的結果賦值給 count 結果為 1;

第七步:A 線程將結果 count =1 刷回到主內存;

第八步:B 線程將結果 count =1 刷回到主內存;

相信大家此時已經非常清晰地分析出了原子性產生的根本原因了。

至于解決方案可以通過鎖或者是 CAS 的方式。具體方案就不再這里贅述了。

2、可見性

萬丈高樓平地起,再復雜的技術我們也需要從基本的概念看起來:

可見性:一個線程對共享變量的修改,另外一個線程能夠立刻看到,我們稱為可見性。

2.1、可見性問題產生的原因

在很多年前,那個嫁妝只需要一個手電筒的年代你或許還不會出現可見性這樣的問題,因為大家都是單核處理器,不存在并發的情況。

而對于現在“視金錢如糞土”的年代。多核處理器已經是現代超級計算機的基礎硬件。高速的CPU處理器和緩慢的內存之前數據的通信成了矛盾。

所以為了解決和緩和這樣的情況,每個CPU和線程都有自己的本地緩存,所謂本地緩存即該緩存僅僅對它所在的處理器可見,CPU緩存與內存的數據不容易保證一致。

為了避免這種因為寫數據速度不一致而導致 CPU 的性能浪費的情況,處理器通過使用寫緩沖區來臨時保存待寫入主內存的數據。寫緩沖區合并對同一內存地址的多次寫,并以批處理的方式刷新,也就是說寫緩沖區不會立即將數據刷新到主內存中

緩存不能及時刷新到主內存就是導致可見性問題產生的根本原因。

2.2、案例分析

public class AtomicDemo {private int count = 0;public void add() {count++;}public int get() {return count;}public static void main(String[] args) throws InterruptedException {CountDownLatch countDownLatch = new CountDownLatch(100);AtomicDemo atomicDemo = new AtomicDemo();IntStream.rangeClosed(0, 100).forEach(item -> {new Thread(() -> {IntStream.rangeClosed(1, 100).forEach(i -> {atomicDemo.add();});}).start();countDownLatch.countDown();});countDownLatch.await();System.out.println(atomicDemo.get());} }

“what * *”,怎么和上面代碼一樣。。。結果就不截圖了,必然不是10000。

我們來看下執行的流程圖(PS:不要糾結于為什么和上面的不一樣,特定問題特定分析。在闡述一種問題的時候,一定會在某些層面上屏蔽另外一種問題的干擾)

假設 A 線程和 B 線程同時開始執行,首先 A 線程和 B 線程會將主內存中的 count 的值加載/緩存到自己的本地內存中。然后會讀取各自的內存中的值去執行操作,也就是說此時 A 線程和 B 線程就好像是兩個世界的人,彼此不會產生人和關聯。

操作完之后 A 線程將結果寫回到自己的本地內存中,同樣 B 線程將結果寫回到自己的本地內存中。然后回來某個時機各自將結果刷會到主內存。那最終必然是一方的數據被另一方覆蓋。這就是緩存的可見性問題

3、有序性

不積跬步無以至千里,我們還是先來看概念

有序性:程序執行的順序按照代碼的先后順序執行。

這有啥的,程序老老實實按照程序員寫的代碼執行就完事了,這還會有什么問題嗎?

3.1、有序性問題產生的原因

實際上編譯器為了提高程序執行的性能。會改變我們代碼的執行順序的。即你寫在前面的代碼不一定是先被執行完的。

例如:int a = 1;int b =4;從表面和常規角度來看,程序的執行應該是先初始化 a ,然后初始化 b 。但是實際上非常有可能是先初始化 b,然后初始化 a。因為在編譯器看了來,先初始化誰對這兩個變量不會有任何影響。即這兩個變量之間沒有任何的數據依賴。

指令重排序有三種類型,分別為:

編譯器優化的重排序。編譯器在不改變單線程程序語義的前提下,可以重新安排語句的執行順序。

指令級并行的重排序。現代處理器采用了指令級并行技術(Instruction-Level Parallelism,ILP)來將多條指令重疊執行。如果不存在數據依賴性,處理器可以改變語句對應 機器指令的執行順序。

內存系統的重排序。由于處理器使用緩存和讀/寫緩沖區,這使得加載和存儲操作看上 去可能是在亂序執行。

3.2、案例分析

有序性的案例最常見的就是 DCL了(double check lock)就是單例模式中的雙重檢查鎖功能。先來看下代碼

public class SingletonDclDemo {private SingletonDclDemo(){}private static SingletonDclDemo instance;public static SingletonDclDemo getInstance(){if (Objects.isNull(instance)) {synchronized (SingletonDclDemo.class) {if (Objects.isNull(instance)) {instance = new SingletonDclDemo();}}}return instance;}public static void main(String[] args) {IntStream.rangeClosed(0,100).forEach(item->{new Thread(SingletonDclDemo::getInstance).start();});} }

這個代碼還是比較簡單的。

在獲取對象實例的方法中,程序首先判斷 instance 對象是否為空,如果為空,則鎖定SingletonDclDemo.class 并再次檢查instance是否為空,如果還為空則創建 Singleton的一個實例。看似很完美,既保證了線程完全的初始化單例,又經過判斷 instance 為 null 時再用 synchronized 同步加鎖。但是還有問題!

instance = new SingletonDclDemo(); 創建對象的代碼,分為三步: ① 分配內存空間; ② 初始化對象SingletonDclDemo; ③ 將內存空間的地址賦值給instance;

但是這三步經過重排之后: ① 分配內存空間 ② 將內存空間的地址賦值給instance ③ 初始化對象SingletonDclDemo

會導致什么結果呢?

線程 A 先執行 getInstance() 方法,當執行完指令②時恰好發生了線程切換,切換到了線程B上;如果此時線程B也執行 getInstance() 方法,那么線程B在執行第一個判斷時會發現instance!=null,所以直接返回instance,而此時的instance是沒有初始化過的,如果我們這個時候訪問instance的成員變量就可能觸發空指針異常。

繼續來張圖來更直觀的理解下:

具體的執行流程在上面已經分析了。相信這張圖片一定能讓你徹底理解。

4、本文小結

并發編程的學習和使用并非一朝一夕的事情,也并非會幾個理論就能寫好優質的并發程序。這需要長時間的實踐和總結。好的代碼很少是寫出來的,都是迭代和優化的。

總結

以上是生活随笔為你收集整理的学妹问我,并发问题的根源到底是什么?的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 免费一级片 | 国产主播福利在线 | 国产性―交一乱―色―情人 | 在线观看污 | 麻豆亚洲 | 色狠狠一区二区三区香蕉 | 三级视频在线观看 | 蜜桃av噜噜一区二区三区 | 亚色中文 | 青娱乐免费在线视频 | 成人免费视频大全 | 久久久久久久网 | 最新黄色在线 | 男人天堂亚洲天堂 | 91国模少妇一区二区三区 | 国产av不卡一区二区 | www.rihan | 龚玥菲三级露全乳视频 | 黄频在线观看 | 亚洲国产一区在线观看 | 91爱爱com | 已满十八岁免费观看 | 国产女主播在线播放 | 青青草国产在线视频 | 天堂视频在线免费观看 | 色在线免费 | 97人妻精品一区二区三区 | 久草a在线 | 深爱激情站 | 欧美日韩国产在线观看 | 小香蕉影院 | 成人在线播放网站 | 欧美色图五月天 | 最新视频在线观看 | 无码人妻一区二区三区在线 | 哈利波特3在线观看免费版英文版 | 国产伦精品视频一区二区三区 | 久久久久久综合网 | 欧美成人做爰猛烈床戏 | 韩日欧美 | 亚洲精品乱码久久久久久国产主播 | 国产成人一区二区三区影院在线 | 免费精品视频在线 | 全国男人天堂网 | 国产精品夜夜爽张柏芝 | 国产美女作爱视频 | 婷婷精品视频 | 男人天堂网址 | 美女毛片在线 | 欧美不卡三区 | 无码国产色欲xxxxx视频 | 在线免费激情视频 | 国产欧美精品一区二区色综合 | 精品综合网 | 女同性αv亚洲女同志 | 久久精品国产精品亚洲色婷婷 | 亚洲精品亚洲 | 精品午夜一区二区 | 国产裸体永久免费视频网站 | 毛片一二三区 | 17c在线观看| 每日av在线 | 狠狠婷婷 | 日韩一级成人 | www.四虎com | 看毛片看毛片 | 高清黄色一级片 | 国产情侣露脸自拍 | 女裸全身无奶罩内裤内衣内裤 | 欧美精品日韩少妇 | 国产综合久久久久久鬼色 | 亚洲天堂麻豆 | 风韵多水的老熟妇 | 天天射综合 | 日本色视 | 2020av在线| 九九精品在线视频 | 五级 黄 色 片 | 91成人久久| 色图18p| 日日干日日摸 | 国内精品人妻无码久久久影院蜜桃 | 91桃色在线观看 | 在线啪| 日本久久免费 | 国产白丝一区二区三区 | 最新黄网 | 久热在线视频 | 欧美资源 | 国产区视频 | av在线伊人 | 在线久| 91成人短视频在线观看 | 国产乱女淫av麻豆国产 | 欧美一级不卡视频 | 精久久久久久久 | 男女草逼网站 | 精品欧美激情精品一区 | 无码人妻aⅴ一区二区三区69岛 |