點(diǎn)餐場(chǎng)景并發(fā)知識(shí)點(diǎn)小紀(jì)

場(chǎng)景

我們現(xiàn)在有一個(gè)餐館名叫王小二菜館,用戶(hù)會(huì)不時(shí)的訪問(wèn)我們的在線點(diǎn)餐系統(tǒng),這個(gè)系統(tǒng)的核心功能是點(diǎn)餐,我們做這個(gè)需求的逐步迭代:

  1. 用戶(hù)訪問(wèn)我們系統(tǒng)時(shí),我們返回歡迎光臨王小二菜館;
  2. 用戶(hù)訪問(wèn)我們系統(tǒng)時(shí),我們返回歷史訪問(wèn)情況歡迎光臨王小二菜館,您是第N位客戶(hù);
  3. 用戶(hù)訪問(wèn)我們系統(tǒng)時(shí),我們返回目前的點(diǎn)餐情況歡迎光臨王小二菜館,您的取餐號(hào)為X,您前面還有N位進(jìn)餐用戶(hù),請(qǐng)耐心等待...,用戶(hù)可以手工刷新查看最新排隊(duì)號(hào);
  4. 什么?都9102年了,還要用戶(hù)手工刷新?用戶(hù)進(jìn)入頁(yè)面后,不想手工刷新,需要實(shí)時(shí)查看就餐情況;

方案

針對(duì)上面提出的逐步迭代的需求,我們來(lái)各個(gè)擊破,并總結(jié)其中涉及到的關(guān)鍵知識(shí)點(diǎn):

這里假設(shè)我們只有一臺(tái)應(yīng)用服務(wù)器

1. 用戶(hù)訪問(wèn)我們系統(tǒng)時(shí),我們返回歡迎光臨王小二菜館;

有過(guò)編程經(jīng)歷的童鞋一定會(huì)說(shuō),這個(gè)問(wèn)題難道不是基本操作嗎?還需多言?我們java猿兒只需開(kāi)啟一個(gè)tomcat,引入spring-mvc,寫(xiě)一個(gè)controller,輕輕松松get一分,So easy!
當(dāng)然思路肯定是這樣,不過(guò)這里需要提出的是,tomcat作為一個(gè)應(yīng)用服務(wù)器,其實(shí)已經(jīng)為我們做好了請(qǐng)求承接和請(qǐng)求分發(fā)的事兒,所以我們只用簡(jiǎn)簡(jiǎn)單單寫(xiě)一段代碼就輕松搞定,其實(shí)這兒還是有很大學(xué)問(wèn)的,如何接收用戶(hù)請(qǐng)求以及分發(fā)請(qǐng)求其實(shí)都是tomcat幫我們透明處理了,tomcat在這做這些事情時(shí)其實(shí)干了兩個(gè)關(guān)鍵的事兒:

  • 接收請(qǐng)求:tomcat需要建立一個(gè)本地socket鏈接來(lái)處理每一次請(qǐng)求;
  • 請(qǐng)求分發(fā):針對(duì)每一次請(qǐng)求,tomcat需要做協(xié)議解析得到相應(yīng)的請(qǐng)求體,并根據(jù)配置好的線程模型來(lái)分發(fā)這次請(qǐng)求,默認(rèn)tomcat是BIO模型即每個(gè)請(qǐng)求一個(gè)線程,然后每個(gè)線程執(zhí)行我們相應(yīng)代碼的邏輯,返回歡迎光臨王小二菜館,需要注意的是這些線程由一個(gè)線程池進(jìn)行維護(hù),每次請(qǐng)求都會(huì)從這個(gè)線程池中獲取,如果并發(fā)請(qǐng)求過(guò)多則會(huì)引發(fā)排隊(duì);

知識(shí)點(diǎn):應(yīng)用服務(wù)器、線程模型、線程池;

2. 用戶(hù)訪問(wèn)我們系統(tǒng)時(shí),我們返回歷史訪問(wèn)情況歡迎光臨王小二菜館,您是第N位客戶(hù);

在簡(jiǎn)單介紹了應(yīng)用服務(wù)器后,我們暫且先不深挖,關(guān)注問(wèn)題您是第N位客戶(hù),這不就是一個(gè)簡(jiǎn)單的計(jì)數(shù)器嗎?So easy,我定義一個(gè)全局變量,來(lái)一個(gè)請(qǐng)求+1不就ok了嘛,這又是一道送分題??
不過(guò)等等,我們剛剛講到,每個(gè)請(qǐng)求都會(huì)從線程池拿出一個(gè)線程,如果我們定義一個(gè)全局變量,這里我們一定能夠保證每個(gè)請(qǐng)求+1后,后續(xù)線程都能看到最新的值嗎?這可不一定呢,另外,同時(shí)來(lái)了多個(gè)線程,他們同時(shí)+1,那么是不是就少算了呀?
這里就碰到了我們經(jīng)典的一致性問(wèn)題了,同一個(gè)共享變量,一個(gè)線程寫(xiě)入,下一個(gè)線程一定可以看到嗎?多個(gè)一起寫(xiě),最后的數(shù)據(jù)一定可以保證符合預(yù)期嗎?
有過(guò)一定經(jīng)驗(yàn)的童鞋肯定會(huì)說(shuō),加個(gè)鎖吧,一步到位,當(dāng)然這是一種解決方法,我們還有更好的方法呢。

知識(shí)點(diǎn):可見(jiàn)性、順序性、鎖;

3. 用戶(hù)訪問(wèn)我們系統(tǒng)時(shí),我們返回目前的點(diǎn)餐情況歡迎光臨王小二菜館,您的取餐號(hào)為X,您前面還有N位進(jìn)餐用戶(hù),請(qǐng)耐心等待...;

這應(yīng)該是我們平時(shí)經(jīng)常碰到的情況:需求很短,范圍很大,無(wú)形需求最為致命??
讓我們來(lái)詳細(xì)分解,首先每個(gè)用戶(hù)要有一個(gè)排隊(duì)號(hào),另外要知道目前有多少用戶(hù)正在進(jìn)餐,另外前面用戶(hù)吃完后,需要通知第X位用戶(hù)可以就餐,且取餐號(hào)越小,越快就位。
每個(gè)用戶(hù)一個(gè)排隊(duì)號(hào),嗯,這是已知題,pass;
前面有多個(gè)用戶(hù)進(jìn)餐,且他們吃完后通知,嗯哼,這個(gè)問(wèn)題可是有那么點(diǎn)難度呀,這里我們可以使用兩個(gè)數(shù)據(jù)結(jié)構(gòu),一個(gè)用于保存目前正在進(jìn)餐的用戶(hù)列表L1,一個(gè)保存目前正在排隊(duì)的用戶(hù)列表L2,叫號(hào)請(qǐng)求過(guò)來(lái)時(shí),先生成順序號(hào),然后看L1是否滿,如果滿了就放到L2,L1里面的用戶(hù)吃完后,從L2取一個(gè)放入L1,bingo,不過(guò)這兒我們需要注意的問(wèn)題是,L1和L2都是需要支持多個(gè)線程訪問(wèn)的,需要保證線程安全。

知識(shí)點(diǎn):并發(fā)容器、線程安全;

4. 什么?都9102年了,還要用戶(hù)手工刷新?用戶(hù)進(jìn)入頁(yè)面后,不想手工刷新,需要實(shí)時(shí)查看就餐情況;

猿兒:這難道不是一個(gè)送分題?我三十秒刷新一次,不就行了。
PM:什么,三十秒鐘,五秒鐘我都嫌長(zhǎng)了,用戶(hù)不耐煩走了怎么辦?轉(zhuǎn)換率誰(shuí)來(lái)負(fù)責(zé)?
被暴擊后的猿兒頓時(shí)阻塞,開(kāi)始了長(zhǎng)達(dá)五秒鐘的沉默,空氣瞬間凝固...
猿兒別心灰意冷,每一次暴擊都是你成長(zhǎng)的機(jī)會(huì),??
這里提供一個(gè)不那么優(yōu)雅的方案,我們?cè)O(shè)計(jì)一個(gè)信號(hào)量字典,key是用戶(hù)順序號(hào),value是一個(gè)信號(hào)量,默認(rèn)信號(hào)量被征用,然后用戶(hù)排隊(duì)請(qǐng)求過(guò)來(lái)如果需要排隊(duì),那么在對(duì)應(yīng)信號(hào)量上面做超時(shí)等待,5秒超時(shí),當(dāng)L1用戶(hù)用餐完畢拿到下一個(gè)排隊(duì)順序號(hào),釋放信號(hào)量,該用戶(hù)即可就餐,嗯哼,not bad。
當(dāng)然,這個(gè)方案有一定風(fēng)險(xiǎn),第一題我們講過(guò),應(yīng)用服務(wù)器默認(rèn)會(huì)使用一個(gè)線程來(lái)處理當(dāng)前請(qǐng)求,線程陷入等待,那豈不是線程池可用線程-1,服務(wù)器可用風(fēng)險(xiǎn)+1,這里我們期待更好的解決方案??。

知識(shí)點(diǎn):信號(hào)量,線程等待、線程喚醒

ok, 到這里,我們就我們四個(gè)小需求做了簡(jiǎn)單的設(shè)計(jì),里面也引出了一些并發(fā)編程的關(guān)鍵知識(shí)點(diǎn),也解決了我們的任務(wù),??+4,??。
等等,這些知識(shí)點(diǎn)都只是提出來(lái)了而已呀,還沒(méi)具體講解呢,別著急,后續(xù)我會(huì)開(kāi)一個(gè)小系列來(lái)專(zhuān)門(mén)整理講解這些知識(shí)點(diǎn),敬請(qǐng)期待~

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容