你好,我是一個線程
一個線程的自傳:出生、死亡和重生。
圖片來源 Justin Lim于 Unsplash
1. 一個新手
我是一個線程。我出生時的號碼是0x3704,然后被帶到一個黑暗的房間,在那里我找到了很多和我一樣的朋友。
我的同伴0x6900在這里呆了相當(dāng)長的時間。他用一種老練的語氣對我說。"我們這些人的命運就是處理包裹。你必須在處理完包裹后立即回到這里,否則你可能永遠不會回來。"
我天真地問道。"包裹?什么包?"
"別擔(dān)心,你很快就會發(fā)現(xiàn)的。我們這里不養(yǎng)閑人。"
沒過多久,門就開了。一個兇神惡煞的家伙大喊:"0x3704,出來!"
一個沉重的包裹壓在我身上。還有一份列出操作步驟的文件。
"走,出去處理這個包裹。"
"但去哪里呢?"
"遵循指示。首先到 "可運行車間"。"
我在地上發(fā)現(xiàn)了一個箭頭。它把我引向一間明亮的房子,里面已經(jīng)容納了一些線人。每個人似乎都很緊張,隨時準(zhǔn)備沖上前去。
我一進來就聽到無線電說:"0x3704,進入運行車間。"
我走得更快了。有人在我身后說話。
"這樣一只幸運的狗!他能在可跑之后馬上跑起來!"
"也許他認識某個人。"
"不,他有更高的優(yōu)先權(quán)。唉!"。"
運行車間就在我面前。它是如此美麗。難怪老線程一直嘮叨說他想永遠留在這里。
房間更大,視野更好??諝馇逍露曳?。有許多工人等著為我服務(wù)。
它們都有數(shù)字。更重要的是,它們有 "硬盤"、"數(shù)據(jù)庫"、"內(nèi)存"、"網(wǎng)卡 "等標(biāo)簽。
只是當(dāng)時我不知道他們的工作。讓我們檢查一下操作步驟。
第一步 解開參數(shù)的包裝
里面有一個HttpRequest對象,包括兩個參數(shù):userName和password。
第二步 進行登錄操作
嗯,有人試圖登錄。我把用戶名和密碼交給了數(shù)據(jù)庫服務(wù)員。他慢慢地離開了。
但他為什么這么慢呢?總之,我可以在這里多待一會兒,因為第三步是不能操作的。
就在這時,廣播說:"0x3704,我是CPU。記住你要走的步驟,然后馬上帶著包裹離開!"。"
我慢慢地開始收拾我的東西。
"快點,另一條線即將進入。"
我離開這個車間,進入另一個大房間,里面有很多線程在喝茶,懶洋洋地打牌。
"老兄,你現(xiàn)在無事可做?"
"你一定是新來的。我正在等待數(shù)據(jù)庫服務(wù)員給我的數(shù)據(jù)。據(jù)說他們的速度比我們慢幾十萬倍。讓我們在這里好好休息一下吧。"
"他們多慢啊!我這里有人在等著登錄,他們能等那么久嗎?"
"放松,難道你不知道現(xiàn)實中的一天等于CPU的一年嗎?我們的時間是以納秒和毫秒計算的。因此,現(xiàn)實中的一秒鐘相當(dāng)于我們世界中的幾天。我們肯定能做到這一點。"
也許我可以睡一會兒了。一段時間后,擴音器又開始工作了。"0x3704,你的數(shù)據(jù)來了,去執(zhí)行吧!"
我轉(zhuǎn)身跑向CPU車間,才發(fā)現(xiàn)這是一扇單向的門。我無法通過這扇門進入車間。
后面?zhèn)鱽硪魂囖Z然大笑。"他肯定是個新手。他甚至不知道我們需要在 "可運行車間 "等待!"
我匆匆趕到可運行車間。這次很不走運,我等了很久才進入CPU車間。
當(dāng)我在等待時,我聽到人們在竊竊私語。
"你知道嗎,最近有一個線程被殺了。"
"但為什么?"
"那個人拒絕離開CPU車間,導(dǎo)致CPU利用率保持100%。所以他被殺了。"
"當(dāng)時他在哪里?"
"也許他是作為一個垃圾被收集起來的。"
我偷偷地打了個寒顫,加快了工作速度。第二步已經(jīng)完成。
第三步 成功登錄后建立主頁
這一步有點耗費時間,因為有很多HTML需要處理。不管是誰寫的代碼,對我來說都是一個惱人的工作。
當(dāng)我忙著操作HTML時,CPU又開始大叫。
"0x3704,這里是CPU。記住你所運行的步驟,然后馬上帶著包裹離開!"。"
"我為什么要這樣做?"
"每個線程只能在CPU上運行一段時間,然后就會輪到其他人。因此,請到可運行車間等待輪到你。"
然后我在 "可運行"、"等待 "和 "運行 "之間多次切換,最后按照步驟表完成了工作。
最后,包含HTML的包被成功送回。至于登錄后的情況,我并不關(guān)心。馬上就要回到我的小黑屋了。我覺得有點不甘心。
但與其他一些螺紋相比,我已經(jīng)很幸運了。它們在手術(shù)后被完全摧毀,而我還活著!"。
回到小黑屋,我被老線程0x6900問住了。
"你的第一天怎么樣了?"
"我們這個世界的規(guī)則很復(fù)雜。首先,你不知道什么時候輪到你;其次,在執(zhí)行過程中,你可能隨時被打斷,被要求離開CPU車間;第三,一旦有涉及硬盤或數(shù)據(jù)庫的耗時操作,你需要離開CPU等待;第四,即使你有數(shù)據(jù),也有可能不能馬上開始工作。你得等著CPU來調(diào)度。"
"夠了,伙計。"
"我只是不明白為什么有些線程在完成工作后就死了,而我們還活著。"
"你知道嗎,永恒是我們的特權(quán)。我們的地方有一個正式的名字:線程池。"
2. 取得進展
作為一個線程,我的日常生活是由撿拾包裹、處理包裹和回到線池,我的黑暗家園組成的。
有一天,當(dāng)我回來的時候,我聽到一位弟兄說:"今天好好休息吧。明天將是一個瘋狂的日子。"我看了看日歷,明天是11月的第四個星期五。
果然,當(dāng)午夜的鐘聲響起時,那些人類開始瘋狂地遞送包裹。為了應(yīng)對大量涌入的包裹,線程庫中沒有人能夠閑下來。我們所有人都出去處理包裹了。CPU車間的利用率超級高。硬盤在嗡嗡作響,網(wǎng)卡的燈在瘋狂閃爍。雖然我們非常努力地工作,但包裹還是迅速堆積起來。
我們也無能為力。有太多的包裹,主要是瀏覽網(wǎng)頁、下訂單、購買、購買和購買。
包裹堆逐漸消失了。我終于可以喘口氣了。我想我永遠不會忘記今天。
通過這些,我意識到我生活的世界是一個電子商業(yè)網(wǎng)絡(luò)。
我每天做的工作是處理登錄、瀏覽、購物車、訂單和付款。
我問老工人0x6900:"我們應(yīng)該工作多長時間?"
"直到系統(tǒng)重新啟動。"0x6900說。
"你曾經(jīng)經(jīng)歷過系統(tǒng)重啟嗎?"
"不,系統(tǒng)重新啟動將是我們的葬禮挽歌。它是啟示錄。一旦系統(tǒng)重啟,整個線程庫將被摧毀。時間和空間都將消逝。一切都會重新開始。"
"那么是什么時候呢?"
"我不能說。只是享受你的日子。"
生活其實是很豐富多彩的。我最喜歡的套餐是上傳圖片。由于網(wǎng)絡(luò)很慢,我可以在CPU車間呆很長時間,遇到很多有趣的線程。
例如,我遇到了線程Memcached。他告訴我,在他的幫助下,電子商業(yè)網(wǎng)絡(luò)保存了許多用戶數(shù)據(jù),而且它們分布在許多機器上。
我問他:"難怪登錄操作變得更快。將沒有必要從數(shù)據(jù)庫中提取數(shù)據(jù),因為你已經(jīng)有了這些數(shù)據(jù)。哦,對了,既然你是分布式的,你有沒有去過其他機器?"
"不,我只能通過網(wǎng)絡(luò)向那臺機器發(fā)送GET和PUT命令來訪問數(shù)據(jù)。我不知道別的。"
上一次,當(dāng)我在等待時,我遇到了一個為數(shù)據(jù)庫連接工作的線程。直到那時我才意識到,還有一個連接池,幾乎和我們的線程池一模一樣。
"有些包裹實在是太變態(tài)了。他們要求看一整年的訂單數(shù)據(jù),這讓我很難受,"他告訴我。
我說。"來吧,這對你來說是純粹的數(shù)據(jù)。在你發(fā)送這些數(shù)據(jù)后,我必須將其構(gòu)建為HTML,這比你的工作要變態(tài)得多!"。"
然后他給了我一個建議。"你必須與Memcached保持良好的關(guān)系,這樣我們才能直接從他那里獲取數(shù)據(jù)。讓我們盡量不要頻繁地調(diào)用數(shù)據(jù)庫。這樣,我們JDBC連接的生活就會輕松很多。"
"當(dāng)然可以。關(guān)鍵是你需要提前將數(shù)據(jù)保存在緩存中,否則我必須詢問緩存,發(fā)現(xiàn)沒有數(shù)據(jù),然后再求助于你。"
這就是生活。如果你不去找點樂子,你的生活怎么可能變得有意義?
3. 狹隘的逃亡
幾天前,我經(jīng)歷了一件可怕的事情。我差點死在線程池外。事實上,我應(yīng)該能預(yù)見到這一點。我當(dāng)時非常不小心。
那天我處理了一些來自HTTP的存款和提款,老線0x6900特別告訴我。"在處理這些包時,你需要非常小心。你必須先獲得一個鎖。當(dāng)你從賬戶中存款或取款時,記得要鎖定賬戶。否則,其他線程會闖入并造成一些損失。在我年輕的時候,我的粗心造成了很大的麻煩。
為了 "恐嚇",好心的0x6900給了我兩張表,內(nèi)容如下。
銀行賬戶。賬戶A,余額為1000美元
- 線程1:存款
- 線程2:提款
表1-1 已解鎖的多線程
表1-2 鎖定的多線程
我很震驚:忘記鎖定賬戶會造成如此嚴(yán)重的事故。從此以后,每當(dāng)我看到存取時,我都會極其小心地處理它。幸運的是,沒有發(fā)生意外。
今天,我收到一個包裹,內(nèi)容是將錢從一個著名演員的賬戶轉(zhuǎn)到一個著名導(dǎo)演的賬戶。我不會透露名字,但我可以告訴你,錢的數(shù)額真的很大。
按照舊線程的命令,我鎖定了演員的賬戶,然后是導(dǎo)演的賬戶。
但令我驚訝的是,還有另一條線程,是的,0x7954,同時從導(dǎo)演的賬戶轉(zhuǎn)錢到演員的賬戶。
目前的情況是這樣的。
起初我不知道發(fā)生了什么事。我等了又等。幾十秒過去了,什么也沒發(fā)生。我以前從未經(jīng)歷過這樣的事件。
這時我看到了0x7954號線程。他坐在那里悠閑地喝咖啡。我問他。
"伙計,我看到你在喝第八杯咖啡,你為什么不去完成你的工作?"
"好吧,你正在喝你的第九杯茶。你為什么不工作?"
"我在等待一把鎖。一些混蛋就是不放。"
"我也在等待一把鎖。如果我知道誰在保管它,我會把他打死。"0x7954兇狠地回答。
我偷看了他一眼,才發(fā)現(xiàn)他正拿著導(dǎo)演的鎖。這正是我一直在等待的!
很明顯,0x7954也發(fā)現(xiàn)我持有的是他一直在等待的鎖。
很快,我們兩個人就打了起來。
"把你的鎖給我,讓我先完成!"。"
"不可能。在我完成我的工作之前,我不會釋放這個鎖。你現(xiàn)在不能擁有它!"。"
爭吵變成真正的戰(zhàn)斗只需要幾毫秒的時間。
更重要的是,我們兩個人不僅持有這位著名導(dǎo)演和演員的鎖,還持有許多其他的鎖。越來越多的人加入了等待的隊伍,圍觀的人擠滿了整個屋子。最后,這真的成了一件大事。我們的大老板 "操作系統(tǒng)",我以前從來沒有見過,他在這里。畢竟,大老板知道的更多。他看著我們,哼了一聲,不屑地說道。
"又是死鎖。"
"你們中的一個將被殺死。你們兩個到這里來,抽簽決定。"
它只是把我嚇壞了。我戰(zhàn)戰(zhàn)兢兢地抽了簽。幸運的是,我活下來了。
在被迫交出所有資源后,可憐的0x7954不幸被殺,消失了。我得到了導(dǎo)演的鎖,現(xiàn)在可以開始工作了。大老板的 "操作系統(tǒng) "像一陣風(fēng)一樣消失了,只有他的聲音跟著消失了。
"記住,在我們這里,導(dǎo)演>演員,這意味著你需要在第一時間得到導(dǎo)演的鎖定。"
因為這里不僅有導(dǎo)演和演員,還有很多人,大老板留下了一張表格,上面有計算資源大小的算法。計算之后,我們需要把鎖從大到小。
(p.s.資源 "大小 "的計算是指通過把資源變成數(shù)字來進行比較。例如,我們可以通過字符串的hascode進行比較。)
我又回到了線程池中。每個人都聽說了我的冒險,并不斷向我詢問細節(jié)。
面目邪惡的線程調(diào)度員把大老板的算法放在墻上。
每天早上,我們必須站在門前,以搞笑的方式大聲背誦。
"記住資源鎖定的順序。記住要根據(jù)Boss的算法進行比較。記住從大到小的鎖定。"
4. 再見
許多天后,我和其他線程發(fā)現(xiàn)了一件奇怪的事情:包裹的處理越來越容易了。不管是登錄、瀏覽還是存錢,步驟都是一樣的。一切都會回到一個固定的HTML頁面。
有一次我偷偷地瞥了一眼,看到上面寫著。" 系統(tǒng)將于今晚00:00至4:00進行維護和升級。給您帶來的不便,我們深感抱歉。"
我把這件事告訴了0x6900。他嘆了口氣。
"唉,我們的生命已經(jīng)走到了盡頭。系統(tǒng)很快就會重新啟動,我們會消失。再見,我的兄弟。"
然后這一刻終于來了。我看到房間里的東西一個接一個地消失了:等待車間、Runnable車間,甚至CPU車間。我身邊的線人兄弟越來越少了。最后,只剩下我一個人了。
我在空曠的地面上大喊。"還有人嗎?"
沒有答復(fù)。
這一代的線程池已經(jīng)完成了它的使命。
然而,下一代人即將重生。