摘要:兜底任務,處理數(shù)據(jù)不一致狀態(tài)的任務。什么是多線程多線程是并發(fā)的一種重要形式。通過具體的多線程問題引出多線程編程中的關鍵點和對應的工具與知識點,輕松學會多線程編程。
這篇文章的目的并不是想教你如何造火箭(面試造火箭,工作擰螺絲),而是想通過對原理和應用案例的有限度剖析來協(xié)助你構建起并發(fā)的思維,并將操作系統(tǒng)的理論知識與工程實踐結合起來,貫穿從學到會的全過程。當然,雖然我們是從實用角度出發(fā),但具有實踐意義的深層次知識點永遠會是面試中的殺手锏,這可比只能口頭造火箭的理論知識更吸引面試官。
本文適合誰:
希望能了解并發(fā)概念的初學者
需要理清并發(fā)概念與技術的工程師
對并發(fā)在工作中的應用與其底層實現(xiàn)原理感興趣的讀者
在這篇文章中,你將了解到并發(fā)與多線程相關的一系列概念,通過一些例子我們可以在不糾結于具體的技術細節(jié)的情況下形成對并發(fā)與多線程相關的各種概念的抽象理解。有了這些概念以后,我們再去學習具體的理論和技術細節(jié)就是手到擒來的事了。
什么是并發(fā)?最近幾年淘寶發(fā)展得如火如荼,涌現(xiàn)出了一大批白手起家的賣家。想象一下你是一個剛剛起步的小賣家,自己運營一個服裝網(wǎng)店,每天都要自己打包發(fā)貨。剛開始時生意一般,每天自己一個人一個小時就能干完。
隨著生意的蓬勃發(fā)展,發(fā)貨時間慢慢地從一個小時漲到了兩個小時、四個小時,一次因為延遲發(fā)貨導致被投訴之后,你終于覺得該招更多的人了。很快,兩個小伙伴加入了你的事業(yè),打包速度開始有了質的提高。這就是最基本的并發(fā)了,每個人都可以看成是一個線程,同樣的工作量,干得人多了自然就快了。
所以并發(fā)就是通過多個執(zhí)行器同時執(zhí)行一個大任務來縮短執(zhí)行時間、提高執(zhí)行效率的方法。
數(shù)據(jù)競爭但是好景不長,周末一盤貨,你發(fā)現(xiàn)少了不少。這辦公室里也沒遭賊,怎么就會少貨呢?細細一查快遞單,你發(fā)現(xiàn)竟然有幾單發(fā)重了。之后的幾天你都細細留意了一下發(fā)貨的過程,最后發(fā)現(xiàn)是因為每個人都會拿著一張發(fā)貨清單去備貨,如果有一些訂單不小心打印重復了,就有可能會被不同的人重復發(fā)貨。雖然數(shù)量不多,但是也很心痛啊。這個問題產生的原因就是因為每個人在備貨之前拿到的訂單狀態(tài)(未發(fā)貨)在實際備貨時發(fā)生了變化(已由其他人發(fā)貨)。這種對一個共享數(shù)據(jù)(訂單的發(fā)貨狀態(tài))本應獨占的讀取、檢查、修改過程,如果發(fā)生了并發(fā),這種情況就被稱為數(shù)據(jù)競爭。而這個讀取、檢查、修改的過程就被稱為臨界區(qū),臨界區(qū)指的就是一個存在數(shù)據(jù)競爭的代碼片段。
數(shù)據(jù)競爭出現(xiàn)的根本原因是一個數(shù)據(jù)本來應該只能由一個執(zhí)行器完整地執(zhí)行讀取、檢查、修改過程,但是如果出現(xiàn)了并發(fā),那么就沒辦法保證到了“修改”這一步時的數(shù)據(jù)還保持了“讀取”時的值了。
確定原因后,有人想到了一個好辦法,可以打印一張總的發(fā)貨清單,這樣所有人都必須以這個清單上的訂單是否發(fā)貨來確定是否要對訂單進行備貨并發(fā)貨了。因為清單只有一份,所以每次只能由一個人來修改訂單的發(fā)貨狀態(tài)。這種只能由一個執(zhí)行器進行數(shù)據(jù)修改操作來避免發(fā)生數(shù)據(jù)競爭問題的做法就被稱為互斥,也就是我們常說的鎖了。
分布式并發(fā)概念 分布式因為你管理得當,生意發(fā)展得很快,現(xiàn)在的辦公室里已經堆不下所有衣服了。所以你又租了一個倉庫來同樣進行發(fā)貨。兩個地方都會進行發(fā)貨,那么就可以把每一個倉庫理解為一臺獨立的計算機,這樣通過多臺計算機完成同一任務的方式就可以被稱為分布式,這樣的一組計算機的集合就被稱為集群。
這時候之前用一張紙質的總發(fā)貨清單的數(shù)據(jù)競爭解決方式就行不通了,所以我們需要把這張總發(fā)貨清單放到云端,讓大家可以通過網(wǎng)絡進行編輯,但是每次只能一個人編輯。在這種情況下,我們可以把兩個倉庫各自看成一臺計算機/進程,而每個倉庫里的人就是這個進程中的線程。這樣的話這張總發(fā)貨清單就成為了一個分布式鎖,因為它每次只能有一個人編輯,所以是一個互斥鎖,或者簡稱為鎖;而因為它可以被兩個進程/計算機(倉庫)共同使用,所以被稱為是分布式鎖。
什么是進程/線程?
可以簡單地將進程理解為我們電腦/手機上的一個應用,同一臺手機上的每個App都是一個進程,同一個App在每個手機上也是一個進程。進程和進程之間可以理解為是兩個倉庫,互相之間物理隔離;而線程就是倉庫里的每一個人,他們共享同一個辦公空間。這里的辦公空間就可以理解為操作系統(tǒng)中的虛擬內存空間,但是本文主要討論并發(fā)相關的概念,就不繼續(xù)展開了。
分布式數(shù)據(jù)不一致因為生意比較好,所以所有人都很忙。有時候就會因為有一些人雖然在云端表格上已經勾上了一個訂單,但是一忙就給忙忘了。其他人怕重復發(fā)貨又不會再去處理已經勾上的訂單了,因為這樣導致的未發(fā)貨訂單讓店鋪被投訴了好多次,影響非常大。這種在并發(fā)過程中修改了數(shù)據(jù)狀態(tài)但是沒有完成后續(xù)執(zhí)行的情況就會出現(xiàn)數(shù)據(jù)不一致,即訂單已經被勾上,但實際并沒有發(fā)貨。
但是作為聰明的老板,你又想到了解決的方法。每隔一小時兩個倉庫就會各派一個人檢查一下已經勾上的訂單是否已經都打包完貼上快遞單了。這種每隔一段時間就檢查并處理遺漏的數(shù)據(jù)不一致訂單的任務就被稱為兜底任務。而通過兜底任務實現(xiàn)的在最后所有訂單都會達到數(shù)據(jù)一致狀態(tài)的情況就被稱為最終一致性。
優(yōu)化方式大家可能早就覺得前面介紹的總發(fā)貨清單的方法太傻了,只要每個訂單都只打印一張發(fā)貨清單,由多帶帶一個人去負責分發(fā)清單就可以了,其他人只要處理好自己被分配到的訂單就可以了。最后再加上一個兜底任務對訂單的發(fā)貨情況進行二次校驗基本上就不會發(fā)生漏發(fā)或者重發(fā)的情況了。這種由一個執(zhí)行器進行任務拆分,再由一組執(zhí)行器進行處理,最后再由一個或一組執(zhí)行器進行結果匯總的處理方式就是現(xiàn)在非常流行的map-reduce方法了。這種方法在大數(shù)據(jù)或者程序語言標準庫里都有大量的應用,比如大數(shù)據(jù)領域赫赫有名的Hadoop和Java語言中的ForkJoinPool都使用了這種思想。
回顧在這篇文章中,我們涉及到了以下的技術名詞:
并發(fā),通過多個執(zhí)行器同時執(zhí)行一個大任務來縮短執(zhí)行時間、提高執(zhí)行效率的方法。
數(shù)據(jù)競爭,對一個共享數(shù)據(jù)本應獨占的讀取、檢查、修改過程發(fā)生了并發(fā)的情況。
臨界區(qū),存在數(shù)據(jù)競爭的代碼片段。
互斥鎖(也可以簡稱為“鎖”),同一時間只能由一個執(zhí)行器獲取的實體,用于實現(xiàn)對臨界區(qū)的互斥(只有一個)訪問。
分布式,通過多臺計算機完成同一任務的方式。
集群,一組完成同一任務的機器。
分布式鎖,在不同機器/進程上提供互斥能力的鎖。
數(shù)據(jù)不一致,一系列操作不具有原子性,一部分執(zhí)行成功而另一部分沒有,導致不同數(shù)據(jù)之間存在矛盾,例如訂單已經是發(fā)貨狀態(tài),但是實際沒有發(fā)貨。
兜底任務,處理數(shù)據(jù)不一致狀態(tài)的任務。
最終一致性,通過兜底任務或其他方式保證數(shù)據(jù)不一致的情況最終會消失。
map-reduce,一種任務拆分-執(zhí)行-再合并的任務執(zhí)行方式,可以有效地利用多臺機器、多核CPU的性能。
后記因為并發(fā)的知識范圍很大,而且對于一些抽象概念的傳遞必然會需要花費一些篇幅,所以這個主題將會包含一系列文章,主要覆蓋以下主題:
什么是并發(fā)?
拋開冗長繁雜的技術點,直接理解并發(fā)相關的各種概念。
什么是多線程?
多線程是并發(fā)的一種重要形式。通過具體的多線程問題引出多線程編程中的關鍵點和對應的工具與知識點,輕松學會多線程編程。
常用工具中的并發(fā)實現(xiàn)
通過解析知名開源工具中的并發(fā)方案實現(xiàn)來深入理解并發(fā)編程實踐。
有興趣的讀者可以繼續(xù)關注后續(xù)的文章,在之后的文章中會有對并發(fā)編程、操作系統(tǒng)原語、硬件原語等等理論與實踐知識的詳細介紹與案例。
對數(shù)據(jù)庫索引感興趣的讀者可以了解一下我之前的文章:
數(shù)據(jù)庫索引是什么?新華字典來幫你 —— 理解
數(shù)據(jù)庫索引融會貫通 —— 深入
20分鐘數(shù)據(jù)庫索引設計實戰(zhàn) —— 實戰(zhàn)
數(shù)據(jù)庫索引為什么用B+樹實現(xiàn)? —— 擴展
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉載請注明本文地址:http://systransis.cn/yun/73536.html
摘要:多線程不僅是后端開發(fā)面試中非常熱門的一個問題,也是各種高級工具框架與分布式的核心基石。有興趣的讀者可以參考本系列的第一篇文章來了解一下并發(fā)相關的基本概念當我們在說并發(fā)多線程,說的是什么。 多線程不僅是Java后端開發(fā)面試中非常熱門的一個問題,也是各種高級工具、框架與分布式的核心基石。但是這個領域相關的知識點涉及到了線程調度、線程同步,甚至在一些關鍵點上還涉及到了硬件原語、操作系統(tǒng)等更底...
摘要:最后,我們會通過對源代碼的剖析深入了解線程池的運行過程和具體設計,真正達到知其然而知其所以然的水平。創(chuàng)建線程池既然線程池是一個類,那么最直接的使用方法一定是一個類的對象,例如。單線程線程池單線程線程 我們一般不會選擇直接使用線程類Thread進行多線程編程,而是使用更方便的線程池來進行任務的調度和管理。線程池就像共享單車,我們只要在我們有需要的時候去獲取就可以了。甚至可以說線程池更棒,...
摘要:多線程編程就像一個沼澤,中間遍布各種各樣的陷阱。但是在多線程編程或者說是并發(fā)編程中,有非常多的陷阱被埋在底層細節(jié)當中。線程池類中用于控制線程池狀態(tài)和線程數(shù)的控制變量就是一個類型的字段。 多線程編程就像一個沼澤,中間遍布各種各樣的陷阱。大多數(shù)開發(fā)者絕大部分時間都是在做上層應用的開發(fā),并不需要過多地涉入底層細節(jié)。但是在多線程編程或者說是并發(fā)編程中,有非常多的陷阱被埋在底層細節(jié)當中。如果不知...
摘要:官方對的解釋是進程管理器。對并發(fā)訪問的處理進程和線程從代碼級別來講不支持多線程操作,不能像等語言一樣可以編寫多線程代碼。 關于本篇文章的部分糾正,請參考這篇文章:http://www.cppblog.com/woaido... 首先搞清楚php-fpm與cgi的關系 CGI CGI是一個web server與cgi程序(這里可以理解為是php解釋器)之間進行數(shù)據(jù)傳輸?shù)膮f(xié)議,保證了傳遞的...
閱讀 2819·2021-11-04 16:15
閱讀 3507·2021-09-29 09:35
閱讀 4104·2021-09-22 15:45
閱讀 1446·2019-08-30 15:55
閱讀 1725·2019-08-30 15:44
閱讀 2774·2019-08-29 12:56
閱讀 2731·2019-08-26 13:30
閱讀 2201·2019-08-23 17:00