計(jì)劃寫幾篇文章講述下Java并發(fā)編程,幫助一些初學(xué)者成體系的理解并發(fā)編程并實(shí)際使用,而不只是碎片化的了解一些Synchronized、ReentrantLock等技術(shù)點(diǎn) 。在講述的過程中,也想融入一些相關(guān)技術(shù)、概念的發(fā)展歷史,這樣便于看到其演化過程而更好地進(jìn)行理解 。文字描述上希望是更通俗些,如果閱讀者能在寥寥文字中稍有所得就很滿足了 。
什么是進(jìn)程?在日常使用計(jì)算機(jī)的過程中我們會(huì)用各類的軟件來處理各種事物,比如聽歌、看視頻、寫文檔等等 。對于相對簡單的軟件對應(yīng)于Windows操作系統(tǒng)就是一個(gè)任務(wù),用計(jì)算機(jī)術(shù)語上說也是一個(gè)進(jìn)程;當(dāng)然對于復(fù)雜的軟件在啟動(dòng)的時(shí)候也有啟動(dòng)多個(gè)進(jìn)程 。切實(shí)感受的話,如果熟悉的 Ctrl+Alt+Del 控制臺(tái)任務(wù)管理器上就能看到,如下圖:

文章插圖
途中也可看到每一個(gè)進(jìn)程都有著顯示操作系統(tǒng)分配使用的對應(yīng)CPU、內(nèi)存、磁盤等資源的信息,這也是常可以聽說到的一句話:進(jìn)程是資源分配的最小單位。
如果回到 Java 中,最開始編程時(shí)運(yùn)行的 Main 函數(shù)其實(shí)就是執(zhí)行一個(gè)控制臺(tái)進(jìn)程 。也是另外聽到的描述 進(jìn)程是正在運(yùn)行的程序的實(shí)例。專業(yè)一點(diǎn)定義來說 進(jìn)程是具有一定獨(dú)立功能的程序關(guān)于某個(gè)數(shù)據(jù)集合上的一次運(yùn)行活動(dòng)。
歷史角度上說,進(jìn)程最先是60年代初由 麻省理工學(xué)院的MULTICS系統(tǒng)和IBM公司的CTSS/360系統(tǒng) 引出的 。
從進(jìn)程到線程如果回到60年代,計(jì)算機(jī)其實(shí)是沒有線程的;隨著各行業(yè)系統(tǒng)軟件發(fā)展,進(jìn)程很多缺陷開始凸顯,比如進(jìn)程是有分配資源,在進(jìn)程進(jìn)行切換/創(chuàng)建等時(shí)候其實(shí)時(shí)間也好、內(nèi)存空間也好耗費(fèi)都非常的大 。于是開始了有輕型進(jìn)程等一些設(shè)計(jì)概念,大約到了80年代左右,線程(Threads)正式開始出現(xiàn) 。
從歷史發(fā)展可以看到線程解決進(jìn)程承擔(dān)分配資源等過重的作用而產(chǎn)生的,所以有些操作系統(tǒng)里面一直也有稱之為輕量級進(jìn)程,在進(jìn)程(Process)單詞上加上Lightweight 輕量線程(Lightweight Process),也有說法叫內(nèi)核線程(Kernel thread) 。
同一個(gè)進(jìn)程往往包含多個(gè)線程,是計(jì)算機(jī)操作系統(tǒng)進(jìn)行運(yùn)算調(diào)度的最小單位 。多線程之間是可以共享同一進(jìn)程的資源的 。存在共享,這其實(shí)就代表了 其存在競爭關(guān)系;比如:多個(gè)線程同時(shí)變更同一個(gè)變量的場景 。在Java編程體系下,如何解決這種并發(fā)使用資源的問題,指的就是Java并發(fā)編程 。
什么是并發(fā)問題?用簡單代碼來舉例演示下并發(fā)的問題,定義一個(gè)變量 val 分別使用單線程/多線程的方式來對 int val 執(zhí)行 1000000 次 加1 的操作 。系統(tǒng)在執(zhí)行加1操作,底層其實(shí)包含了讀取val值 和 修改val值的兩個(gè)指令 。因此在多線程執(zhí)行的條件下,沒有使用到Java并發(fā)編程技巧,將會(huì)在操作執(zhí)行 變更val變量上產(chǎn)生并發(fā)操作 。
單線程結(jié)果當(dāng)然會(huì)是 1000000,多線程CPU運(yùn)行由于執(zhí)行次數(shù)較大大概率結(jié)果會(huì)是 小于(<) 1000000 。下圖為筆者運(yùn)行的結(jié)果,“more threads val is 240799 ”。當(dāng)然運(yùn)行多次不一定是 240799,但一般都會(huì)小于(<) 1000000 讀者可以試試 。

文章插圖
顯然多線程并發(fā)的帶來的這種不確定結(jié)果,不是編程設(shè)計(jì)所想要的 。
為什么產(chǎn)生并發(fā)問題【Java并發(fā)編程 | 從進(jìn)程、線程到并發(fā)問題實(shí)例解決】
IntStream.range(0, 1000).forEach(i -> {val +=1; });要詳細(xì)闡述并發(fā)問題的產(chǎn)生,仔細(xì)分析下上述代碼 。計(jì)算機(jī)運(yùn)行程序底層其實(shí)也是一條條指令在執(zhí)行 。對于val +=1 這行語句,編譯完后其實(shí)有4條語句 。
經(jīng)驗(yàn)總結(jié)擴(kuò)展閱讀
- 從緩存入門到并發(fā)編程三要素詳解 Java中 volatile 、final 等關(guān)鍵字解析案例
- 學(xué)習(xí)ASP.NET Core Blazor編程系列五——列表頁面
- centos7中配置java + mysql +jdk+使用jar部署項(xiàng)目
- Java實(shí)現(xiàn)6種常見排序
- 數(shù)據(jù)結(jié)構(gòu)與算法【Java】08---樹結(jié)構(gòu)的實(shí)際應(yīng)用
- 學(xué)習(xí)ASP.NET Core Blazor編程系列四——遷移
- 二 Java之POI導(dǎo)出Excel:多個(gè)sheet
- 15 JavaObject類
- 【設(shè)計(jì)模式】Java設(shè)計(jì)模式 - 命令模式
- Redis高并發(fā)分布式鎖詳解
