8. 告別Locknode
不是一直說Lock比較麻煩危險嗎,那就不要好了。其實有一個Lock free的方法。數據庫
首先引入一個概念——原子變量。在這種變量上的操做是原子操做(atomic operation)。原子操做就是說這個操做要麼都完成,要麼都不完成,部分完成是不行的。就像物理化學中的原子同樣,借用不可再分的意思。按照這樣理解,對這個原子變量的訪問操做就一定是串行的。一個原子操做完成後才能進行另外一個原子操做。這樣子的變量類型多半是基本變量,什麼int啊double啊boolean啊之類。編程
就能夠簡單這樣想,只要調用原子操做,就能保證對象的串行訪問。設計模式
經常使用語言原子操做內部實現基本用到了鎖。原子操做經常使用的有++,--,compare & swap。特別地,這個CAS(compare and swap)配合循環操做就能實現lock free方法。看下面的stack.push(…)僞代碼。架構
1 Atomic<Node*> head; 2 Node* new_node= new Node(….); 3 New_node->next=head; (1) 4 While(!head.compare_and_swap(new_node->next, new_node)); (2)
設有一個Stack,須要push一個值進去,head指針申明爲原子量。(1)把新值的next設爲head。(2)更新head,若是head==new_node->next那麼,head=new_node,返回true,跳出循環;不然new_node->next更新爲head,並返回false,繼續循環。猜測?什麼狀況會new_node->next不等於head?若是在(1)執行完畢後head被其它線程修改。此時的old_head(new_node->next)就須要更新爲當前最新的head,才能進行接下來的操做。這種方式實現的stack push就是用了lock free思想。是否是比加lock代碼看起來簡潔多了? 代碼中一個lock操做都沒有看到哦。併發
Lock free須要一個自旋鎖,耗CPU時間,而lock方法是直接block住,釋放佔用的CPU時間。發現沒?這個「自旋鎖」思想在前文的try lock中也出現了?甚至能夠這樣猜測,若是把全部的鎖都換成自旋鎖,是否是就能防止死鎖了?前面的stack.push操做也能夠添加CAS試作次數,操做必定次數或時間限制,表示這次push失敗,也就跳出了此自旋鎖。另外,沒有所謂的lock free就是比lock好,根據不一樣的業務狀況,自行選擇吧。分佈式
問:若是個人關鍵實體是一個對象,那麼能夠把對象最爲一個原子量嗎?這個,恐怕不能,不過能夠分解對象中的一些基本類型字段做爲原子量。到底使用哪些基本類型,須要對業務需求有深入的理解。函數式編程
9. 輪詢操做函數
觀察者設計模式這裏很少說了,主要思想是把主動輪詢,轉變爲被動通知。不過在某些併發程序集中「輪詢」比「通知」思想還要廣泛,或者說「經過輪詢來通知」。甚至這樣說,我感受在某些場合輪詢比通知更有用,特別是對順序要求敏感的地方。這類程序基於規避亂序風險從而選擇此架構方式,並且輪詢的架構方式能人爲製造「程序柵欄」。Thread barrier這個操做據說過吧,這是一種同步程序的方式。這種方式在某些分佈式程序中用到(特別是消息隊列模塊),並且很是利於Debug。性能
一個完整的系統輪詢和通知都很重要,沒有誰好誰很差一說。寫到這裏想一想,在上文輪詢中,提到「順序」兩個字,你懂的,順序執行容易引起性能瓶頸,及其連鎖反應。並且輪詢數據庫什麼的,數據多起來能直接把系統搞得不響應好嗎,考慮下觸發器嘛。因此架構就是一種舍一種得的心態,要根據具體業務需求來定奪。
「通知」的理解之後有機會再說。對了,輪詢時記得yield, 別到時候輪詢線程一跑起來把CPU時間片佔光了,其它併發操做受到影響。
10. 線程操做
線程是執行一個函數,頗有函數式編程理念的感受。可是並非線程開得越多程序處理就越快,這和實際處理器數和線程上下文切換頻率就很大關係,這些狀況baidu google一下就知道,不細說,基本上最好的線程數量就大概是空閒處理器的數量。
這裏說的一個思想是線程池Thread pool。就是說線程建立後不會由於執行完畢而被銷燬,它會放入一個池子中等待新任務喚醒它,而後開始執行。線程建立是要耗CPU資源的,重複利用固然是好的。這個功能在高級語言中有對應的實現,好比說C#的task,它的默認調度類就實現了此思想。因此說高級語言使用起來比較順暢,你不用從頭開始造輪子。C++的boost庫中也有相似方法。編程的時候用上唄,何樂而不爲?
如上圖,2個線程作5個任務,而不是用5個線程。並且在task3以後,線程1就處於空轉或阻塞的等待狀態而不是銷燬自身,直到task4出現又開始執行。可是,若是5個task並行執行,且確實有如此多空閒處理器,開5條線程,處理效率更高。線程池的方式是否適用此場景還需好好考慮下。
咱們看得稍微抽象點,前文所說的線程池技術,就是任務調度操做,這個之後有機會在說吧。。。
to be continue...