Ⅰ 【Redisson】Semaphore 鎖源碼剖析
Semaphore 信號量: 允許多個線程同時獲取一把鎖,任何一個線程釋放鎖後,其他睜信等待的一個線程就可以嘗試獲取鎖。
舉個栗子: 憑證有3個,10個線程去搶
輸出結果:
對應參數做友如下:悉胡輪
RedissonSemaphore#tryAcquire() 中的 lua 腳本:
Ⅱ 《源代碼》燒腦片還是反戰片 只要您的大腦足夠燃燒請來一探究竟
這部電影上映後非常受歡迎。評分一度高達8分以上。
我模糊記得曾經於上映當年看過此片,但卻沒有多少回憶。
難道我也如影片中男主一樣,生活在了虛擬空間里???
當然我在開玩笑。
影片的燒腦邏輯劇情是大家喜歡的原因。
我我看完也非常喜歡,只是看到最後稍稍有些傷感。
影片的燒腦我覺得只是一個表現方式,其實這部影片想表達的思想卻更為含蓄而無奈。
我把他定義為反戰片,看完這部電影後或許會贊同我的觀點。
影片簡介,男主卡爾特,被無緣無故拖進了一個無限循環的列車爆炸案中 。
而更可怕的是在這個無限爆炸案中,男主無論怎麼死都會在一個固定地方重生。
而他生存的唯一目的就是找出爆炸事件的兇手。
究竟是如何造成這樣的局面?
我們一起拭目以待。。。。
一切都是那麼的突然而又陌生。卡爾特還沒反應,坐在對面的美女克里斯蒂娜(後面簡稱小娜),向卡爾特打招呼,並稱呼他為肖恩。
陌生的環境,認錯自己的陌生人,行駛的列車讓卡爾特莫名其妙。
在觀看了周圍的環境後,卡爾特離開座位來到衛生間。而衛生間的鏡子讓他頓然失措。
鏡子里竟然映出的是另外一個男人的面孔。
卡爾特連忙搜索全身口袋,在皮夾子里他發現他的身份信息確實變成了肖恩,也就是鏡中人。
小娜發現了卡爾特的失常,當然在她眼中他是肖恩。她過來安慰卡爾特。
話音剛落,列車隨即爆炸。
蘇醒後,他發現自己在一個小黑屋。與外界的聯系只有一個顯示屏。
而顯示屏的另外一端是身著軍裝的美女,她在向卡爾特詢問某些信息。
通過了解這位美女知道自己的真實身份,同時卡爾特也知道美女名叫古德溫。
而古德溫並沒有過多回答卡爾特的疑問,只是要求卡爾特調查爆炸列車的主謀。
隨著一段網路傳輸,卡爾特回到的剛才的列車,同樣的場景,同樣的人物再次出現。
他開始注意列車中每一個人的動作,樣貌,著裝及言語。
一個簡單的細節引起的他的注意,一個下車的旅客遺落了自己的錢包,被乘客撿到送還。
卡爾特趕到時乘客已經離開。這樣不起眼的線索顯然無法引起足夠的重視。
憑借多年的戰爭經驗,卡爾特迅速回到車廂。他開始搜尋炸彈的所在位置。
炸彈連接著手機,看來手機通訊即可會引起爆炸。
於是他將假證件冒充公職人員,禁止撥打電話,以保護列車的安全。
話音剛落,爆炸再次開啟。卡爾特又失敗了。
再次回到小黑屋的卡爾特有點崩潰。人只能經歷一次生死,而他短短10幾分鍾就經歷兩次生死。
古德溫是個心地善良的人。她感受到卡爾特的痛苦及哀求。她決定向上級請求。
經過請示,古德溫告訴卡爾特。這次他必須找到炸彈嫌疑人。
因為目前卡爾特所經歷的就是早間發生的實實在在的爆炸事故。
軍人的天職讓卡爾特意識到問題的嚴重性。他決定再次執行任務。
同時他知道了自己只有 8分鍾 的時間,時間過後不論如何他都會被再次傳送回來。
8分鍾能幹什麼?對於拯救整部列車乘客來說,似乎太難了。
卡爾特第三次被傳送至列車。
這次他選擇救下小娜的性命改變爆炸的內容。同時注意去廁所的人就是嫌犯。
然而在車站找到了所謂的「嫌犯」後才發現根本自己找錯了方向,而列車再次爆炸。
卡爾特則不小心掉下鐵軌被火車撞死。這樣他再次回到小黑屋。
古德溫監測到卡爾特的失敗訊號。小黑屋與總台失去聯系。
失聯的小黑屋裡電力中斷,室內溫度急劇下降。卡爾特恐怕堅持不了多久。
憑借著超強的修復能力,卡爾特利用工具恢復電力。
這次的通話中,卡爾特告訴古德溫,他救了一個女孩。
這似乎能夠改變整個事件的性質,然而得到的答案讓卡爾大失所望。
古德溫告訴卡爾特其實那一切都是假的。他其實變成了一個源代碼。
源代碼是一個比較高深的問題,在電影中我們可以把它理解為一個神經信號。
一段記憶,一段電子錄像,一個開發程序等等。
其實就是死者肖恩的大腦存儲的8分鍾記憶(也就是現在卡爾特所扮演的角色)
總之一句話,就是非現實存在的重復利用場景,雖然看似現實,其實都是虛幻的假象。
聽到這里卡爾特無法接受。如果這些都成立的話,那麼卡爾特也就是不復存在的人。
顯示屏一側人員根本沒有讓卡爾特喘息和思考的機會。
古德溫告訴他,必須盡快找到犯罪嫌疑人,因為而犯罪嫌疑人揚言要將整個芝加哥引爆。
顯然古德溫等人一直在利用卡爾特說服他完成任務。這次他們為卡爾特提供了武器支持。
卡爾特無奈只能第四次返回 8分鍾記憶空間 。然而這次的武器加成並沒有帶來什麼用處。
被乘警制服後,醒來的卡爾特發現為時已晚。
小娜並不知道實情,卡爾特告訴他,生命只有一分鍾了。他想打電話給自己的父親。
隨後列車發生爆炸。
再次失敗的卡爾特向古德溫提出想要給自己的父親打個電話,因為他並不認為自己已經死去。
古德溫再次勸說卡爾特繼續完成任務,並許諾可以在任務結束後答應一定的請求。
有點失去耐心的卡爾特無奈第5次返回 8分鍾 空間。這次他的主要目的是搜索乘客背包,找尋證據。
然而這次的搜索依然毫無進展,反而通過小娜的手機得知自己確實在戰爭中身亡。
8分鍾的第五次經歷再次失敗。回到小黑屋的卡爾特一臉懵,他不相信這是事實。
明明一切都是如此的真實,卡爾特始終不相信自己已經死亡。
面對卡爾特受盡摧殘的意識,古德溫的內心受到強烈的譴責。
她道出實情。卡爾特確實死去,只保留大腦機能,他們在利用卡爾特殘存的意識進行任務。
得知真實消息的卡爾特根本無法接受這種說辭。
畢竟在如此超現實的源代碼中,大腦意識是根本無法接受如此的假象。
卡爾特向古德溫的領導控訴,然而美國對逝去軍人的做法更是讓人憤慨。
他們竟然通過合法手段對戰死海外的軍人進行二次利用。
而且卡爾特的家屬根本不知道他的遺體還在這里進行二次實驗。
這可以算是對美國人權有力回擊。算是抨擊自己政府的戰爭野心及對軍人的褻瀆。
事實於此,該組織領導乾脆不聽卡爾特的話,直接開始強行讓他穿梭。
如果卡爾特無法完成任務,那麼他將永遠持續在這8分鍾的無限循環。
這種感覺比6道輪回還要折磨人,在威逼利誘之下,卡爾特第6次返回8分鍾記憶。
這次他選擇先將炸彈手機引爆裝置拆除,看能否拖延一些時間。
通過手機號碼的回撥他終於鎖定了犯罪嫌疑人。(就是第2次穿梭時那個遺落錢包的壞蛋)
隨後卡爾特在車站旁停車場追捕到嫌疑人。
而車里就是足以將整個芝加哥毀滅的自製核武器。
正當勝利在握時,小娜的出現打破了均衡,疑犯趁機擊倒卡爾特,將小娜擊殺。
嫌疑人隨後揚長而去。隨後8分鍾到,火車再次爆炸。
雖然列車再次爆炸,但重要的是疑犯被鎖定,車輛被確認。
隨後警方按照卡爾特提供的信息快速地鎖定疑犯車輛,此案算是高一段落。
全源代碼部門都在歡呼,他們忽略了卡爾特的感受,他們踐踏了人性的尊嚴,他們在為自己的政績而歡呼雀躍。
他們並沒有打算遵從卡爾特的意願讓他安息,反而把他當成搖錢樹,要清除記憶反復使用。
古德溫是直面卡爾特的第一連線員,她的良心在卡爾特痛苦的神情面前微微顫抖。
古德溫做出一個大膽的決定,讓卡爾特長眠,不要他再受折磨。
但卡爾特在走之前對古德溫提出一個要求,那就是讓他再回一次8分鍾世界去拯救那一車人。
不只是回去拯救那一車人,更重要的是他愛上了小娜。
在那個世界裡他的意識已經混入現實,而現實世界已經變成了他的虛擬世界。
這種邏輯背離關系確實沒有任何瑕疵,在卡爾特的意識里那才是真正的現實世界。
最後一次回到8分鍾世界,他輕松地抓住了嫌犯,並且將炸彈全部拆除。
8分鍾的時間在這里他綽綽有餘。於是他把電話打給了自己的父親。
誠然他不能說出自己的名字,他以朋友的身份跟自己父親最後一次通話。
這通天堂電話讓人落淚。卡爾特滿足了最後的人生願望。他將勝利的消息以簡訊的形式發給了古德溫。
在最後的一分鍾里,卡爾特向小娜表白。因為這是他們相聚的最後一次。
古德溫在現實世界按下了終止卡爾特生命持續的按鈕。
隨後雖然領導強烈反對,但古德溫還是做出了自己的選擇,將卡爾特解脫。
8分鍾里的畫面戛然而止。那一秒種,時間靜止了。
影片本以為到此結束。隨後意外的一幕發生了。
火車並沒有爆炸,那個世界真的迎來了幸福的曙光。
卡爾特以肖恩的身份與心愛的小娜在另外一個世界幸福的生活。
小娜並不知道自己在現實世界已經離去,而卡爾特則非常珍惜現在的來之不易。
他們站在了城市廣場的鏡面雕塑前,許願美好的人生。
鏡中的城市倒影彷彿成為了真實世界的縮影。
而在另外的真實世界,古德溫則收到了一條莫名其妙的簡訊。
簡訊正是卡爾特在8分鍾里發出的最後回復消息,古德溫對這條簡訊非常疑惑。
令人意外的是,她顯然對此事毫無所知。於是她趕緊向領導報告。
而辦公室里領導已經知道此事,並將嫌犯逮捕。
古德溫此時非常意外,她只能離開。顯然她對此事一無所知,甚至不知道卡爾特等信息。
而此時的源代碼部門又投入了緊張的工作中。
卡爾特是誰,曾經發生過的一切都隨之消失。
這里是平行空間,還是平行鏡像空間,還是混亂的時間空間?
導演沒有給你最後的答案。
這里可能是一個輪回的時間周期也說不準。
總之,新的源代碼事件會再次發生。
到底是誰活在源代碼的空間里,誰活在現實空間已經無從考究。
這里成為了死循環的開始也是終點。
這部電影的主題是源代碼,但我卻從中看到人性的考驗。
影片諷刺了美國政府的人權尊嚴,表達了對發動各種無理由戰爭死傷軍士的憐憫和懷念。
為國犧牲卻連最起碼的尊嚴都沒有留給自己,這算哪門子的人權。
最終男主與父親的對話卻讓人動容。
這到底是燒腦片還是反戰片,我遲遲不好定論。
不知各位朋友如何看待此片?喜歡的朋友可以留言。
今天我們就聊到這,下期再見。
謝謝關注。
Ⅲ 誰有老游戲「風雲之天下會」的游戲源代碼
要物品代碼么?
0E 魚腸劍 0F 吳鉅劍 10 寒玉劍 11 連城劍
12 紫程 13 青竹劍 14 軒轅劍 15 青紅劍
16 金霞劍 17 龍吟劍 18 白虎劍 19 青索劍
1A 飛煙劍 1B 巨闕劍 1C 湛廬劍 1D 昆無劍
1E 墨劍 1F 混元劍 20 小龍泉 21 俠王劍
22 干將 23 莫邪 24 無雙神劍 25 英雄劍
26 火麟劍 27 絕世好劍 28 短刀 29 菜刀
2A 柴刀 2B 雙手刀 2C 一般長刀 2D 狼牙刀
2E 鯊刀 2F 紂膠刀 30 砍刀 31 驚蟄刀
32 青玉麒 33 靼藏刀 34 斬馬刀 35 槍刀
36 苗刀 37 羽常刀 38 蝶野刀 39 黃金掃刀
3A 清梵刀 3B 鈴蛇刀 3C 彪殘刀 3D 瀛倭刀
3E 柳陽刀 3F 清陽刀 40 地煞 41 金蝠刀
42 赤紋龍 43 百鬼鳴 44 日月蝕 45 雪飲
46 赤竹胄 47 檀木護胸 48 紅旗戰甲 49 羅漢護衣
4C 墨軍鎖甲 4D 赭金鎖片 4E 波斯赤甲 4F 頑鋃銅甲
50 震天戰袍 51 漢武戰袍 52 烏鋼金甲 53 鬼魅披風
54 東皇寶甲 55 龍麟鎖衣 56 冥王戰甲 57 青雲戰袍
5A 翡翠護腕 5B 流星 5C 指日輪 5D 寒玉
5E 雙月 5F 百鬼印輪 60 天轉聖輪 61 黑蛇
63 千手纏 63 殛雷震 64 藍貂 65 鱗甲
66 羅剎 67 日光臂環 68 雲蟒 69 蒼龍
6A 月影臂環 6B 木靈 6C 玄甲 6D 紅蓮臂刀
6E 丹鳳 6F 赤蠍 70 柳煙 71 百眼
72 離釣 78 項圈 79 紅緞帶 7A 護身符
7B 玉器 7C 赤蠶絲 7D 密宗珠 7E 忍者面當
7F 藍水晶 80 青罡 81 月牙 82 國士無雙
83 焚雲石 84 青銅 85 謎之首飾 86 赤炎石
87 修羅 88 金蘭結 89 玉修羅 8A 金剛
8B 神威 8C 鬼迫 8D 封神戒 8E 封神戒
96 包子 97 豬肉 98 人參 99 千年人參
9A 大還丹 9B 六陽正氣丹 9C 生生造化丹 9D 雪蛤膏
9E 天香斷續膠 9F 靈芝 A0 千年靈芝 A1 九轉雄蛇丸
A2 乾坤一氣丸 A3 鎮心理氣丸 A4 花露九 A5 紫心丸
A6 水靈丸 A7 回陽五龍膏 A8 虎膽丸 A9 蛇膽丸
AA 玉靈散 AB 玉蜂漿 AC 定神丹 AD 黃蓮丸
AE 還魂丹 AF 金梅酒 B0 璃清酒 B1 雪片紅雨
B2 醒獅曇 B3 爆雷彈 B4 火焰彈 B5 煙霧彈
B6 火麟彈 B7 魂魄彈 B8 掌心雷 B9 紫雲香
BA 夜叉神王咒 BB 多聞天王咒 BC 增長天王咒 BD 廣目天王咒
BE 持國天王咒 BF 不動冥王咒 C0 千手觀音咒 C1 金剛羅漢咒
C2 雷音風神咒 C3 帝釋天神咒 C4 布告紙 C5 信函
C6 金鑰匙 C7 銀鑰匙 C8 錦盒 C9 發簪
CA 翡翠人偶 CB 乾坤劍 CC 鬼珠 CD 玉刀
CE 勾玉 CF 銅鑰匙 D0 鐵鑰匙 D1 王水
Ⅳ 國內重要的 Go 語言項目:TiDB 3.0 GA,穩定性和性能大幅提升
TiDB 是 PingCAP 自主研發的開源分布式關系型資料庫,具備商業級資料庫的數據可靠性,可用性,安全性等特性,支持在線彈性水平擴展,兼容 MySQL 協議及生態,創新性實現 OLTP 及 OLAP 融合。
TiDB 3.0 版本顯著提升了大規模集群的穩定性,集群支持 150+ 存儲節點,300+TB 存儲容量長期穩定運行。易用性方面引入大量降低用戶運維成本的優化,包括引入 Information_Schema 中的多個實用系統視圖、EXPLAIN ANALYZE、SQL Trace 等。在性能方面,特別是 OLTP 性能方面,3.0 比 2.1 也有大幅提升,其中 TPC-C 性能提升約 4.5 倍,Sysbench 性能提升約 1.5 倍,OLAP 方面,TPC-H 50G Q15 因實現 View 可以執行,至此 TPC-H 22 個 Query 均可正常運行。新功能方面增加了窗口函數、視圖(實驗特性)、分區表、插件系統、悲觀鎖(實驗特性)。
截止本文發稿時 TiDB 已在 500+ 用戶的生產環境中長期穩定運行,涵蓋金融、保險、製造,互聯網, 游戲 等領域,涉及交易、數據中台、 歷史 庫等多個業務場景。不同業務場景對關系型資料庫的訴求可用 「百花齊放」來形容,但對關系資料庫最根本的訴求未發生任何變化,如數據可靠性,系統穩定性,可擴展性,安全性,易用性等。請跟隨我們的腳步梳理 TiDB 3.0 有什麼樣的驚喜。
3.0 與 2.1 版本相比,顯著提升了大規模集群的穩定性,支持單集群 150+ 存儲節點,300+TB 存儲容量長期穩定運行,主要的優化點如下:
1. 優化 Raft 副本之間的心跳機制,按照 Region 的活躍程度調整心跳頻率,減小冷數據對集群的負擔。
2. 熱點調度策略支持更多參數配置,採用更高優先順序,並提升熱點調度的准確性。
3. 優化 PD 調度流程,提供調度限流機制,提升系統穩定性。
4. 新增分布式 GC 功能,提升 GC 的性能,降低大集群 GC 時間,提升系統穩定性。
眾所周知,資料庫查詢計劃的穩定性對業務至關重要,TiDB 3.0 版本採用多種優化手段提升查詢計劃的穩定性,如下:
1. 新增 Fast Analyze 功能,提升收集統計信息的速度,降低集群資源的消耗及對業務的影響。
2. 新增 Incremental Analyze 功能,提升收集單調遞增的索引統計信息的速度,降低集群資源的消耗及對業務的影響。
3. 在 CM-Sketch 中新增 TopN 的統計信息,緩解 CM-Sketch 哈希沖突導致估算偏大,提升代價估算的准確性,提升查詢計劃的穩定性。
4. 引入 Skyline Pruning 框架,利用規則防止查詢計劃過度依賴統計信息,緩解因統計信息滯後導致選擇的查詢計劃不是最優的情況,提升查詢計劃的穩定性。
5. 新增 SQL Plan Management 功能,支持在查詢計劃不準確時手動綁定查詢計劃,提升查詢計劃的穩定性。
1. OLTP
3.0 與 2.1 版本相比 Sysbench 的 Point Select,Update Index,Update Non-Index 均提升約 1.5 倍,TPC-C 性能提升約 4.5 倍。主要的優化點如下:
1. TiDB 持續優化 SQL 執行器,包括:優化 NOT EXISTS 子查詢轉化為 Anti Semi Join,優化多表 Join 時 Join 順序選擇等。
2. 優化 Index Join 邏輯,擴大 Index Join 運算元的適用場景並提升代價估算的准確性。
3. TiKV 批量接收和發送消息功能,提升寫入密集的場景的 TPS 約 7%,讀密集的場景提升約 30%。
4. TiKV 優化內存管理,減少 Iterator Key Bound Option 的內存分配和拷貝,多個 Column Families 共享 block cache 提升 cache 命中率等手段大幅提升性能。
5. 引入 Titan 存儲引擎插件,提升 Value 值超過 1KB 時性能,緩解 RocksDB 寫放大問題,減少磁碟 IO 的佔用。
6. TiKV 新增多線程 Raftstore 和 Apply 功能,提升單節點內可擴展性,進而提升單節點內並發處理能力和資源利用率,降低延時,大幅提升集群寫入能力。
TiDB Lightning 性能與 2019 年年初相比提升 3 倍,從 100GB/h 提升到 300GB/h,即 28MB/s 提升到 85MB/s,優化點,如下:
1. 提升 SQL 轉化成 KV Pairs 的性能,減少不必要的開銷。
2. 提升單表導入性能,單表支持批量導入。
3. 提升 TiKV-Importer 導入數據性能,支持將數據和索引分別導入。
4. TiKV-Importer 支持上傳 SST 文件限速功能。
RBAC(Role-Based Access Control,基於角色的許可權訪問控制) 是商業系統中最常見的許可權管理技術之一,通過 RBAC 思想可以構建最簡單「用戶-角色-許可權」的訪問許可權控制模型。RBAC 中用戶與角色關聯,許可權與角色關聯,角色與許可權之間一般是多對多的關系,用戶通過成為什麼樣的角色獲取該角色所擁有的許可權,達到簡化許可權管理的目的,通過此版本的迭代 RBAC 功能開發完成。
IP 白名單功能(企業版特性) :TiDB 提供基於 IP 白名單實現網路安全訪問控制,用戶可根據實際情況配置相關的訪問策略。
Audit log 功能(企業版特性) :Audit log 記錄用戶對資料庫所執行的操作,通過記錄 Audit log 用戶可以對資料庫進行故障分析,行為分析,安全審計等,幫助用戶獲取數據執行情況。
加密存儲(企業版特性) :TiDB 利用 RocksDB 自身加密功能,實現加密存儲的功能,保證所有寫入到磁碟的數據都經過加密,降低數據泄露的風險。
完善許可權語句的許可權檢查 ,新增 ANALYZE,USE,SET GLOBAL,SHOW PROCESSLIST 語句許可權檢查。
1. 新增 SQL 方式查詢慢查詢,豐富 TiDB 慢查詢日誌內容,如:Coprocessor 任務數,平均/最長/90% 執行/等待時間,執行/等待時間最長的 TiKV 地址,簡化慢查詢定位工作,提高排查慢查詢問題效率,提升產品易用性。
2. 新增系統配置項合法性檢查,優化系統監控項等,提升產品易用性。
3. 新增對 TableReader、IndexReader 和 IndexLookupReader 運算元內存使用情況統計信息,提高 Query 內存使用統計的准確性,提升處理內存消耗較大語句的效率。
4. 制定日誌規范,重構日誌系統,統一日誌格式,方便用戶理解日誌內容,有助於通過工具對日誌進行定量分析。
5. 新增 EXPLAIN ANALYZE 功能,提升SQL 調優的易用性。
6. 新增 SQL 語句 Trace 功能,方便排查問題。
7. 新增通過 unix_socket 方式連接資料庫。
8. 新增快速恢復被刪除表功能,當誤刪除數據時可通過此功能快速恢復數據。
TiDB 3.0 新增 TiFlash 組件,解決復雜分析及 HTAP 場景。TiFlash 是列式存儲系統,與行存儲系統實時同步,具備低延時,高性能,事務一致性讀等特性。 通過 Raft 協議從 TiKV 中實時同步行存數據並轉化成列存儲格式持久化到一組獨立的節點,解決行列混合存儲以及資源隔離性問題。TiFlash 可用作行存儲系統(TiKV)實時鏡像,實時鏡像可獨立於行存儲系統,將行存儲及列存儲從物理隔離開,提供完善的資源隔離方案,HTAP 場景最優推薦方案;亦可用作行存儲表的索引,配合行存儲對外提供智能的 OLAP 服務,提升約 10 倍復雜的混合查詢的性能。
TiFlash 目前處於 Beta 階段,計劃 2019 年 12 月 31 日之前 GA,歡迎大家申請試用。
未來我們會繼續投入到系統穩定性,易用性,性能,彈性擴展方面,向用戶提供極致的彈性伸縮能力,極致的性能體驗,極致的用戶體驗。
穩定性方面 V4.0 版本將繼續完善 V3.0 未 GA 的重大特性,例如:悲觀事務模型,View,Table Partition,Titan 行存儲引擎,TiFlash 列存儲引擎;引入近似物理備份恢復解決分布資料庫備份恢復難題;優化 PD 調度功能等。
性能方面 V4.0 版本將繼續優化事務處理流程,減少事務資源消耗,提升性能,例如:1PC,省去獲取 commit ts 操作等。
彈性擴展方面,PD 將提供彈性擴展所需的元信息供外部系統調用,外部系統可根據元信息及負載情況動態伸縮集群規模,達成節省成本的目標。
我們相信戰勝「未知」最好的武器就是社區的力量,基礎軟體需要堅定地走開源路線。截止發稿我們已經完成 41 篇源碼閱讀文章。TiDB 開源社區總計 265 位 Contributor,6 位 Committer,在這里我們對社區貢獻者表示由衷的感謝,希望更多志同道合的人能加入進來,也希望大家在 TiDB 這個開源社區能夠有所收獲。
TiDB 3.0 GA Release Notes: https://pingcap.com/docs-cn/v3.0/releases/3.0-ga/
Ⅳ Linux下各種鎖的理解和使用及總結解決epoll驚群問題(面試常考)-
鎖出現的原因
臨界資源是什麼: 多線程執行流所共享的資源
鎖的作用是什麼, 可以做原子操作, 在多線程中針對臨界資源的互斥訪問... 保證一個時刻只有一個線程可以持有鎖對於臨界資源做修改操作...
任何一個線程如果需要修改,向臨界資源做寫入操作都必須持有鎖,沒有持有鎖就不能對於臨界資源做寫入操作.
鎖 : 保證同一時刻只能有一個線程對於臨界資源做寫入操作 (鎖地功能)
再一個直觀地代碼引出問題,再從指令集的角度去看問題
上述一個及其奇怪的結果,這個結果每一次運行都可能是不一樣的,Why ? 按照我們本來的想法是每一個線程 + 20000000 結果肯定應該是60000000呀,可以就是達不到這個值
為何? (深入匯編指令來看) 一定將過程放置到匯編指令上去看就可以理解這個過程了.
a++; 或者 a += 1; 這些操作的匯編操作是幾個步驟?
其實是三個步驟:
正常情況下,數據少,操作的線程少,問題倒是不大,想一想要是這樣的情況下,操作次數大,對齊操作的線程多,有些線程從中間切入進來了,在運算之後還沒寫回內存就另外一個線程切入進來同時對於之前的數據進行++ 再寫回內存, 啥效果,多次++ 操作之後結果確實一次加加操作後的結果。 這樣的操作 (術語叫做函數的重入) 我覺得其實就是重入到了匯編指令中間了,還沒將上一次運算的結果寫回內存就重新對這個內存讀取再運算寫入,結果肯定和正常的邏輯後的結果不一樣呀
來一幅圖片解釋一下
咋辦? 其實問題很清楚,我們只需要處理的是多條匯編指令不能讓它中間被插入其他的線程運算. (要想自己在執行匯編指令的時候別人不插入進來) 將多條匯編指令綁定成為一條指令不就OK了嘛。
也就是原子操作!!!
不會原子操作?操作系統給咱提供了線程的 綁定方式工具呀:mutex 互斥鎖(互斥量), 自旋鎖(spinlock), 讀寫鎖(readers-writer lock) 他們也稱作悲觀鎖. 作用都是一個樣,將多個匯編指令鎖成為一條原子操作 (此處的匯編指令也相當於如下的臨界資源)
悲觀鎖:鎖如其名,每次都悲觀地認為其他線程也會來修改數據,進行寫入操作,所以會在取數據前先加鎖保護,當其他線程想要訪問數據時,被阻塞掛起
樂觀鎖:每次取數據的時候,總是樂觀地認為數據不會被其他線程修改,因此不上鎖。但是在更新數據前, 會判斷其他數據在更新前有沒有對數據進行修改。
互斥鎖
最為常見使用地鎖就是互斥鎖, 也稱互斥量. mutex
特徵,當其他線程持有互斥鎖對臨界資源做寫入操作地時候,當前線程只能掛起等待,讓出CPU,存在線程間切換工作
解釋一下存在線程間切換工作 : 當線程試圖去獲取鎖對臨界資源做寫入操作時候,如果鎖被別的線程正在持有,該線程會保存上下文直接掛起,讓出CPU,等到鎖被釋放出來再進行線程間切換,從新持有CPU執行寫入操作
互斥鎖需要進行線程間切換,相比自旋鎖而言性能會差上許多,因為自旋鎖不會讓出CPU, 也就不需要進行線程間切換的步驟,具體原理下一點詳述
加互斥量(互斥鎖)確實可以達到要求,但是會發現運行時間非常的長,因為線程間不斷地切換也需要時間, 線程間切換的代價比較大.
相關視頻推薦
你繞不開的組件—鎖,4個方面手撕鎖的多種實現
「驚群」原理、鎖的設計方案及繞不開的「死鎖」問題
學習地址:C/C++Linux伺服器開發/後台架構師【零聲教育】-學習視頻教程-騰訊課堂
需要C/C++ Linux伺服器架構師學習資料加qun812855908獲取(資料包括 C/C++,Linux,golang技術,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒體,CDN,P2P,K8S,Docker,TCP/IP,協程,DPDK,ffmpeg 等),免費分享
自旋鎖
spinlock.自旋鎖.
對比互斥量(互斥鎖)而言,獲取自旋鎖不需要進行線程間切換,如果自旋鎖正在被別的線程佔用,該線程也不會放棄CPU進行掛起休眠,而是恰如其名的在哪裡不斷地循環地查看自旋鎖保持者(持有者)是否將自旋鎖資源釋放出來... (自旋地原來就是如此)
口語解釋自旋:持有自旋鎖的線程不釋放自旋鎖,那也沒有關系呀,我就在這里不斷地一遍又一遍地查詢自旋鎖是否釋放出來,一旦釋放出來我立馬就可以直接使用 (因為我並沒有掛起等待,不需要像互斥鎖還需要進行線程間切換,重新獲取CPU,保存恢復上下文等等操作)
哪正是因為上述這些特點,線程嘗試獲取自旋鎖,獲取不到不會採取休眠掛起地方式,而是原地自旋(一遍又一遍查詢自旋鎖是否可以獲取)效率是遠高於互斥鎖了. 那我們是不是所有情況都使用自旋鎖就行了呢,互斥鎖就可以放棄使用了嗎????
解釋自旋鎖地弊端:如果每一個線程都僅僅只是需要短時間獲取這個鎖,那我自旋占據CPU等待是沒啥問題地。要是線程需要長時間地使用占據(鎖)。。。 會造成過多地無端占據CPU資源,俗稱站著茅坑不拉屎... 但是要是僅僅是短時間地自旋,平衡CPU利用率 + 程序運行效率 (自旋鎖確實是在有些時候更加合適)
自旋鎖需要場景:內核可搶占或者SMP(多處理器)情況下才真正需求 (避免死鎖陷入死循環,瘋狂地自旋,比如遞歸獲取自旋鎖. 你獲取了還要獲取,但是又沒法釋放)
自旋鎖的使用函數其實和互斥鎖幾乎是一摸一樣地,僅僅只是需要將所有的mutex換成spin即可
僅僅只是在init存在些許不同
何為驚群,池塘一堆, 我瞄準一條插過去,但是好似所有的都像是覺著自己正在被插一樣的四處逃竄。 這個就是驚群的生活一點的理解
驚群現象其實一點也不少,比如說 accept pthread_cond_broadcast 還有多個線程共享epoll監視一個listenfd 然後此刻 listenfd 說來 SYN了,放在了SYN隊列中,然後完成了三次握手放在了 accept隊列中了, 現在問題是這個connect我應該交付給哪一個線程處理呢.
多個epoll監視准備工作的線程 就是這群 (),然後connet就是魚叉,這一叉下去肯定是所有的 epoll線程都會被驚醒 (多線程共享listenfd引發的epoll驚群)
同樣如果將上述的多個線程換成多個進程共享監視 同一個 listenfd 就是(多進程的epoll驚群現象)
咱再畫一個草圖再來理解一下這個驚群:
如果是多進程道理是一樣滴,僅僅只是將所有的線程換成進程就OK了
終是來到了今天的正題了: epoll驚群問題地解決上面了...
首先 先說說accept的驚群問題,沒想到吧accept 平時大家寫它的多線程地時候,多個線程同時accept同一個listensock地時候也是會存在驚群問題地,但是accept地驚群問題已經被Linux內核處理了: 當有新的連接進入到accept隊列的時候,內核喚醒且僅喚醒一個進程來處理
但是對於epoll的驚群問題,內核卻沒有直接進行處理。哪既然內核沒有直接幫我們處理,我們應該如何針對這種現象做出一定的措施呢?
驚群效應帶來的弊端: 驚群現象會造成epoll的偽喚醒,本來epoll是阻塞掛起等待著地,這個時候因為掛起等待是不會佔用CPU地。。。 但是一旦喚醒就會佔用CPU去處理發生地IO事件, 但是其實是一個偽喚醒,這個就是對於線程或者進程的無效調度。然而進程或者線程地調取是需要花費代價地,需要上下文切換。需要進行進程(線程)間的不斷切換... 本來多核CPU是用來支持高並發地,但是現在卻被用來無效地喚醒,對於多核CPU簡直就是一種浪費 (浪費系統資源) 還會影響系統的性能.
解決方式(一般是兩種)
Nginx的解決方式:
加鎖:驚群問題發生的前提是多個進程(線程)監聽同一個套接字(listensock)上的事件,所以我們只讓一個進程(線程)去處理監聽套接字就可以了。
畫兩張圖來理解一下:
上述還沒有進行一個每一個進程都對應一個listensock 而是多線程共享一個listensock 運行結果如下
所有的線程同時被喚醒了,但是實際上會處理連接的僅僅只是一個線程,
咱僅僅只是將主線程做如上這樣一個簡單的修改,每一個線程對應一個listensock;每一個線程一個獨有的監視窗口,將問題拋給內核去處理,讓內核去負載均衡 : 結果如下
僅僅喚醒一個線程來進行處理連接,解決了驚群問題
本文通過介紹兩種鎖入手,以及為什麼需要鎖,鎖本質就是為了保護,持有鎖你就有權力有能力操作寫入一定的臨界保護資源,沒有鎖你就不行需要等待,本質其實是將多條匯編指令綁定成原子操作
然後介紹了驚群現象,通過一個巧妙地例子,扔一顆石子,只是瞄準一條魚扔過去了,但是整池魚都被驚醒了,
對應我們地實際問題就是, 多個線程或者進程共同監視同一個listensock。。。。然後IO連接事件到來地時候本來僅僅只是需要一個線程醒過來處理即可,但是卻會使得所有地線程(進程)全部醒過來,造成不必要地進程線程間切換,多核CPU被浪費喔,系統資源被浪費
處理方式 一。 Nginx 源碼加互斥鎖處理。。 二。設置SO_REUSEPORT, 使得多個進程線程可以同時連接同一個port , 為每一個進程線程搞一個listensock... 將問題拋給內核去處理,讓他去負載均衡地僅僅將IO連接事件分配給一個進程或線程
Ⅵ java中snchronised和鎖的區別
在分布式開發中,鎖是線程式控制制的重要途徑。Java為此也提供了2種鎖機制,synchronized和lock。
我們先從最簡單的入手,逐步分析這2種的區別。
一、synchronized和lock的用法區別
synchronized:在需要同步的對象中加入此控制,synchronized可以加在方法上,也可以加在特定代碼塊中,括弧中表示需要鎖的對象。
lock:需要顯示指定起始位置和終止位置。一般使用ReentrantLock類做為鎖,多個線程中必須要使用一個ReentrantLock類做為對象才能保證鎖的生效。且在加鎖和解鎖處需要通過lock()和unlock()顯示指出。所以一般會在finally塊中寫unlock()以防死鎖。
用法區別比較簡單,這里不贅述了,如果不懂的可以看看Java基本語法。
二、synchronized和lock性能區別
synchronized是託管給JVM執行的,而lock是java寫的控制鎖的代碼。在Java1.5中,synchronize是性能低效的。因為這是一個重量級操作,需要調用操作介面,導致有可能加鎖消耗的系統時間比加鎖以外的操作還多。相比之下使用Java提供的Lock對象,性能更高一些。但是到了Java1.6,發生了變化。synchronize在語義上很清晰,可以進行很多優化,有適應自旋,鎖消除,鎖粗化,輕量級鎖,偏向鎖等等。導致在Java1.6上synchronize的性能並不比Lock差。官方也表示,他們也更支持synchronize,在未來的版本中還有優化餘地。
說到這里,還是想提一下這2中機制的具體區別。據我所知,synchronized原始採用的是CPU悲觀鎖機制,即線程獲得的是獨占鎖。獨占鎖意味著其他線程只能依靠阻塞來等待線程釋放鎖。而在CPU轉換線程阻塞時姿鄭會引起線程上下文切換,當有很多線程競爭鎖的時候,會引起CPU頻繁的上下文切換導致效率很低。
而Lock用的是樂觀鎖方式。所謂樂觀鎖就是,每次不加鎖而是假設沒有沖突而去跡罩頌完成某項操作,如果因為沖突失敗就重試,直到成功為止。樂觀鎖實現的機制就是CAS操作(Compare and Swap)。我們可以進一步研究ReentrantLock的源代碼,會發現其中比較重要的獲得鎖的一個方法是compareAndSetState。這里其實就是調用的CPU提供的特殊指令。
現代的CPU提供了指令,可以自動更新共享數據,而且能夠檢測到其他線程的干擾,而 compareAndSet() 就用這些代替了鎖定。這個演算法稱作非阻塞演算法,意思是一個線程的失敗或者掛起不應該影響其他線程的失悶凳敗或掛起的演算法。
我也只是了解到這一步,具體到CPU的演算法如果感興趣的讀者還可以在查閱下,如果有更好的解釋也可以給我留言,我也學習下。
三、synchronized和lock用途區別
synchronized原語和ReentrantLock在一般情況下沒有什麼區別,但是在非常復雜的同步應用中,請考慮使用ReentrantLock,特別是遇到下面2種需求的時候。
1.某個線程在等待一個鎖的控制權的這段時間需要中斷
2.需要分開處理一些wait-notify,ReentrantLock裡面的Condition應用,能夠控制notify哪個線程
3.具有公平鎖功能,每個到來的線程都將排隊等候
Ⅶ 源碼解析-偏向鎖撤銷流程解讀
源碼鏈接: http://hg.openjdk.java.net/jdk8u/jdk8u/hotspot/file/9ce27f0a4683/src/share/vm/runtime/biasedLocking.cpp#l146
簡單總結下偏向撤銷的流程:
細節補充:
如何判斷偏向所有者沒有正在持有該偏向鎖?
分兩步,首先判斷偏向所有者是否還活著,如果還活著,則遍歷它的棧,看是否能找到關聯該鎖的鎖記錄,如果找到,則正在持有,如果沒找到,則沒有持有。(遍歷過程在一個安全點執行,此時偏向所有者被阻塞。)
偏向所有者正在持有該偏向鎖,如何將其撤銷為輕量級鎖?
遍歷偏向所有者的棧,修改與該鎖關聯的所有頃橘旅鎖記錄,讓偏向所有者以為它對該對象加的就是輕量級鎖。
源碼中的 highest_lock,為什麼說是最早關聯偏向鎖的鎖記錄呢?
首伍喊先,鎖記錄在棧里是連續存放的。
請求獲取鎖時,按照從低地址到高地址的順序,找在已關聯該鎖的鎖記錄之前,最後一個空閑的鎖記錄(沒有指向雀凳任何鎖對象)。
請求鎖的源碼如下:
而撤銷偏向鎖時,遍歷偏向所有者的鎖記錄,也是按照從低地址到高地址的順序,但它沒有 break 的邏輯,因為它要處理所有關聯該鎖的鎖記錄。所以退出循環後,highest_lock 指向的是最早關聯該鎖的鎖記錄。
這篇: 源碼解析-觸發批量撤銷或批量重偏向的條件 ,介紹了批量撤銷的觸發條件。
包含批量撤銷邏輯的源碼:
禁用類的可偏向屬性有兩點作用:
對於批量撤銷時,正在被線程持有的偏向鎖,通過在安全點遍歷所有 Java 線程的棧,將偏向鎖撤銷為輕量級鎖。