Java 實(shí)現(xiàn)100 萬(wàn)+并發(fā),搞懂這些,騷操作!
Java實(shí)現(xiàn)百萬(wàn)級(jí)并發(fā),需要注意的,三大核心問(wèn)題,你知道嗎?并發(fā)編程并不是一項(xiàng)孤立存在的技術(shù),也不是脫離現(xiàn)實(shí)生活場(chǎng)景而提出的一項(xiàng)技術(shù)。
相反,實(shí)現(xiàn)百萬(wàn)級(jí)并發(fā)編是一項(xiàng)綜合性的技術(shù),同時(shí),它與現(xiàn)實(shí)生活中 的場(chǎng)景有著緊密的聯(lián)系。
搞懂并發(fā)編程有三大核心問(wèn)題
- 分工問(wèn)題
- 同步問(wèn)題
- 互斥問(wèn)題
本文就對(duì)這三大核心問(wèn)題進(jìn)行簡(jiǎn)單的介紹
1、分工問(wèn)題
關(guān)于分工,比較官方的解釋是:一個(gè)比較大的任務(wù)被拆分成多個(gè)大小合適的任務(wù),這些大小合適的任務(wù)被交給合適的線(xiàn)程去執(zhí)行。
分工強(qiáng)調(diào)的是執(zhí)行的性能。
類(lèi)比現(xiàn)實(shí)案例
可以類(lèi)比現(xiàn)實(shí)生活中的場(chǎng)景來(lái)理解分工,例如,如果你是一家上市公司的 CEO,那么,你的主要工作就是規(guī)劃公司的戰(zhàn)略方向和管理好公司。就如何管理好公司而言,涉及的任務(wù)就比較多了。
這里,可以將管理好公司看作一個(gè)很大的任務(wù),這個(gè)很大的任務(wù)可以包括人員招聘與管理、 產(chǎn)品設(shè)計(jì)、產(chǎn)品開(kāi)發(fā)、產(chǎn)品運(yùn)營(yíng)、產(chǎn)品推廣、稅務(wù)統(tǒng)計(jì)和計(jì)算等。如果將這些工作任務(wù)都交給 CEO一個(gè)人去做,那么估計(jì) CEO 會(huì)被累趴下的。CEO一人做完公司所有日常工作如圖1所示。
?
圖1CEO 一人做完公司所有日常工作
如圖1所示,公司 CEO 一個(gè)人做完公司所有日常工作是一種非常不可取的方式,這將導(dǎo)致公司無(wú)法正常經(jīng)營(yíng),那么應(yīng)該如何做呢?
有一種很好的方式是分解公司的日常工作,將人員招聘與管理工作交給人力資源部,將產(chǎn) 品設(shè)計(jì)工作交給設(shè)計(jì)部,將產(chǎn)品開(kāi)發(fā)工作交給研發(fā)部,將產(chǎn)品運(yùn)營(yíng)和產(chǎn)品推廣工作分別交給運(yùn) 營(yíng)部和市場(chǎng)部,將公司的稅務(wù)統(tǒng)計(jì)和計(jì)算工作交給財(cái)務(wù)部。
這樣,CEO 的重點(diǎn)工作就變成了及時(shí)了解各部門(mén)的工作情況,統(tǒng)籌并協(xié)調(diào)各部門(mén)的工作, 并思考如何規(guī)劃公司的戰(zhàn)略。
公司分工后的日常工作如圖2所示。
圖2公司分工后的日常工作
將公司的日常工作分工后,可以發(fā)現(xiàn),各部門(mén)之間的工作是可以并行推進(jìn)的。例如,在人力資源部進(jìn)行員工的績(jī)效考核時(shí),設(shè)計(jì)部和研發(fā)部正在設(shè)計(jì)和開(kāi)發(fā)公司的產(chǎn)品,與此同時(shí),公司的運(yùn)營(yíng)人員正在和設(shè)計(jì)人員與研發(fā)人員溝通如何更好地完善公司的產(chǎn)品,而市場(chǎng)部正在加大力度宣傳和推廣公司的產(chǎn)品,財(cái)務(wù)部正在統(tǒng)計(jì)和計(jì)算公司的各種財(cái)務(wù)報(bào)表等。一切都是那么有條不紊。
所以,在現(xiàn)實(shí)生活中,安排合適的人去做合適的事情是非常重要的。映射到并發(fā)編程領(lǐng)域 也是同樣的道理。
并發(fā)編程中的分工
在并發(fā)編程中,同樣需要將一個(gè)大的任務(wù)拆分成若干比較小的任務(wù),并將這些小任務(wù)交給 不同的線(xiàn)程去執(zhí)行,如圖3所示。
圖3將一個(gè)大的任務(wù)拆分成若干比較小的任務(wù)
在并發(fā)編程中,由于多個(gè)線(xiàn)程可以并發(fā)執(zhí)行,所以在一定程度上能夠提高任務(wù)的執(zhí)行效率。
在并發(fā)編程領(lǐng)域,還需要注意一個(gè)問(wèn)題就是:將任務(wù)分給合適的線(xiàn)程去做。也就是說(shuō),該由主線(xiàn)程執(zhí)行的任務(wù)不要交給子線(xiàn)程去做,否則,是解決不了問(wèn)題的。
這就好比一家公司的 CEO 將規(guī)劃公司未來(lái)的工作交給一位產(chǎn)品開(kāi)發(fā)人員一樣,不僅不能規(guī)劃好公司的未來(lái),甚至?xí)c公司的價(jià)值觀背道而馳。
在Java 中,線(xiàn)程池、Fork/Join 框架和 Future 接口都是實(shí)現(xiàn)分工的方式。在多線(xiàn)程設(shè)計(jì)模式中,Guarded Suspension 模式、Thread-Per-Message 模式、生產(chǎn)者—消費(fèi)者模式、兩階段終止模式、Worker-Thread 模式和 Balking 模式都是分工問(wèn)題的實(shí)現(xiàn)方式。
2、同步問(wèn)題
在并發(fā)編程中,同步指一個(gè)線(xiàn)程執(zhí)行完自己的任務(wù)后,以何種方式來(lái)通知其他的線(xiàn)程繼續(xù)執(zhí)行任務(wù),也可以將其理解為線(xiàn)程之間的協(xié)作,同步強(qiáng)調(diào)的是執(zhí)行的性能。
類(lèi)比現(xiàn)實(shí)案例
可以在現(xiàn)實(shí)生活中找到與并發(fā)編程中的同步問(wèn)題相似的案例。
例如,張三、李四和王五共同開(kāi)發(fā)一個(gè)項(xiàng)目,張三是一名前端開(kāi)發(fā)人員,他需要等待李四的開(kāi)發(fā)接口任務(wù)完成再開(kāi)始渲染 頁(yè)面,而李四又需要等待王五的服務(wù)開(kāi)發(fā)工作完成再寫(xiě)接口。
也就是說(shuō),任務(wù)之間是存在依賴(lài)關(guān)系的,前面的任務(wù)完成后,才能執(zhí)行后面的任務(wù)。
在現(xiàn)實(shí)生活中,這種任務(wù)的同步,更多的是靠人與人之間的交流和溝通來(lái)實(shí)現(xiàn)的。例如,王五的服務(wù)開(kāi)發(fā)任務(wù)完成了,告訴李四,李四馬上開(kāi)始執(zhí)行開(kāi)發(fā)接口任務(wù)。等李四的接口開(kāi)發(fā)完成后,再告訴張三,張三馬上調(diào)用李四開(kāi)發(fā)的接口將返回的數(shù)據(jù)渲染到頁(yè)面上。現(xiàn)實(shí)生活中 的同步模型如圖4所示。
圖4現(xiàn)實(shí)生活中的同步模型
由圖4可以看出,在現(xiàn)實(shí)生活中,張三、李四和王五的任務(wù)之間是有依賴(lài)關(guān)系的,張三渲染頁(yè)面的任務(wù)依賴(lài)?yán)钏拈_(kāi)發(fā)接口的任務(wù)完成,李四開(kāi)發(fā)接口的任務(wù)依賴(lài)王五開(kāi)發(fā)服務(wù)的任務(wù)完成。
并發(fā)編程中的同步
在并發(fā)編程領(lǐng)域,同步機(jī)制指一個(gè)線(xiàn)程的任務(wù)執(zhí)行完成后,通知其他線(xiàn)程繼續(xù)執(zhí)行任務(wù)的方式,并發(fā)編程同步簡(jiǎn)易模型如圖5所示。
圖5并發(fā)編程同步簡(jiǎn)易模型
由圖5可以看出,在并發(fā)編程中,多個(gè)線(xiàn)程之間的任務(wù)是有依賴(lài)關(guān)系的。
線(xiàn)程A 需要阻塞等待線(xiàn)程 B 執(zhí)行完任務(wù)才能開(kāi)始執(zhí)行任務(wù),線(xiàn)程 B 需要阻塞等待線(xiàn)程 C 執(zhí)行完任務(wù)才能開(kāi)始執(zhí)行任務(wù)。線(xiàn)程 C 執(zhí)行完任務(wù)會(huì)喚醒線(xiàn)程 B 繼續(xù)執(zhí)行任務(wù),線(xiàn)程 B 執(zhí)行完任務(wù)會(huì)喚醒線(xiàn)程 A 繼續(xù)執(zhí)行任務(wù)。
這種線(xiàn)程之間的同步機(jī)制,可以使用如下的 if 偽代碼來(lái)表示。
if(依賴(lài)的任務(wù)完成){ 執(zhí)行當(dāng)前任務(wù) }else{ 繼續(xù)等待依賴(lài)任務(wù)的執(zhí)行 }
上述 if 偽代碼所代表的含義是:當(dāng)依賴(lài)的任務(wù)完成時(shí),執(zhí)行當(dāng)前任務(wù),否則,繼續(xù)等待依 賴(lài)任務(wù)的執(zhí)行。
在實(shí)際場(chǎng)景中,往往需要及時(shí)判斷出依賴(lài)的任務(wù)是否已經(jīng)完成,這時(shí)就可以使用 while 循 環(huán)來(lái)代替 if 判斷, while 偽代碼如下。
while(依賴(lài)的任務(wù)未完成){ 繼續(xù)等待依賴(lài)任務(wù)的執(zhí)行 } 執(zhí)行當(dāng)前任務(wù)
上述 while 偽代碼所代表的含義是:如果依賴(lài)的任務(wù)未完成,則一直等待,直到依賴(lài)的任務(wù)完成,才執(zhí)行當(dāng)前任務(wù)。
在并發(fā)編程領(lǐng)域,同步機(jī)制有一個(gè)非常經(jīng)典的模型——生產(chǎn)者—消費(fèi)者模型。如果隊(duì)列已滿(mǎn),則生產(chǎn)者線(xiàn)程需要等待,如果隊(duì)列不滿(mǎn),則需要喚醒生產(chǎn)者線(xiàn)程;如果隊(duì)列為空,則消費(fèi)者線(xiàn)程需要等待,如果隊(duì)列不為空,則需要喚醒消費(fèi)者。
可以使用下面的偽代碼來(lái)表示生產(chǎn)者—消費(fèi)者模型。
生產(chǎn)者偽代碼
while(隊(duì)列已滿(mǎn)){ 生產(chǎn)者線(xiàn)程等待 } 喚醒生產(chǎn)者
消費(fèi)者偽代碼
while(隊(duì)列為空){ 消費(fèi)者等待 } 喚醒消費(fèi)者
在Java 中,Semaphore、Lock、synchronized.、CountDownLatch、CyclicBarrier、Exchanger 和 Phaser 等工具類(lèi)或框架實(shí)現(xiàn)了同步機(jī)制。
3、互斥問(wèn)題
在并發(fā)編程中,互斥問(wèn)題一般指在同一時(shí)刻只允許一個(gè)線(xiàn)程訪問(wèn)臨界區(qū)的共享資源。互斥強(qiáng)調(diào)的是多個(gè)線(xiàn)程執(zhí)行任務(wù)時(shí)的正確性。
類(lèi)比現(xiàn)實(shí)案例
互斥問(wèn)題在現(xiàn)實(shí)中的一個(gè)典型場(chǎng)景就是交叉路口的多輛車(chē)匯入一個(gè)單行道,如圖6所示。
圖6交叉路口的多輛車(chē)匯入一個(gè)單行道
從圖6可以看出,當(dāng)多輛車(chē)經(jīng)過(guò)交叉路口匯入同一個(gè)單行道時(shí),由于單行道的入口只能容納一輛車(chē)通過(guò),所以其他的車(chē)輛需要等待前面的車(chē)輛通過(guò)單行道入口后,再依次有序通過(guò)單行道入口。這就是現(xiàn)實(shí)生活中的互斥場(chǎng)景。
并發(fā)編程中的互斥
在并發(fā)編程中,分工和同步強(qiáng)調(diào)的是任務(wù)的執(zhí)行性能,而互斥強(qiáng)調(diào)的則是執(zhí)行任務(wù)的正確性,也就是線(xiàn)程的安全問(wèn)題。
如果在并發(fā)編程中,多個(gè)線(xiàn)程同時(shí)進(jìn)入臨界區(qū)訪問(wèn)同一個(gè)共享變量,則可能產(chǎn)生線(xiàn)程安全問(wèn)題,這是由線(xiàn)程的原子性、可見(jiàn)性和有序性問(wèn)題導(dǎo)致的。
而在并發(fā)編程中解決原子性、可見(jiàn)性和有序性問(wèn)題的核心方案就是線(xiàn)程之間的互斥。
例如,可以使用JVM中提供的synchronized鎖來(lái)實(shí)現(xiàn)多個(gè)線(xiàn)程之間的互斥,使用synchronized鎖的偽代碼如下。
修飾方法
public synchronized void methodName(){ //省略具體方法 }
修飾代碼塊
public void methodName(){ synchronized(this){ //省略具體方法 }}
public void methodName(){ synchronized(obj){ //省略具體方法 } }
public void methodName(){ synchronized(ClassName.class){ //省略具體方法 } }
修飾靜態(tài)方法
public synchronized static void staticMethodName(){ //省略具體方法 }
除了synchronized 鎖,Java 還提供了 ThreadLocal、CAS、原子類(lèi)和以CopyOnWrite 開(kāi)頭的并發(fā)容器類(lèi)、Lock 鎖及讀/寫(xiě)鎖等,它們都實(shí)現(xiàn)了線(xiàn)程的互斥機(jī)制。
后記
本文節(jié)選自《深入理解高并發(fā)編程:核心原理與案例實(shí)戰(zhàn)》,主要介紹了并發(fā)編程中的三大核心問(wèn)題:分工、同步和互斥,并列舉了現(xiàn)實(shí)生活中的場(chǎng)景進(jìn)行類(lèi)比,以便讀者理解這三大核心問(wèn)題。