● 請你講述一下互斥鎖(mutex)機制,以及互斥鎖和讀寫鎖的區別
參考回答:
1、互斥鎖和讀寫鎖區別:
互斥鎖:mutex,用於保證在任何時刻,都只能有一個線程訪問該對象。當獲取鎖操作失敗時,線程會進入睡眠,等待鎖釋放時被喚醒。
讀寫鎖:rwlock,分為讀鎖和寫鎖。處於讀操作時,可以允許多個線程同時獲得讀操作。但是同一時刻只能有一個線程可以獲得寫鎖。其它獲取寫鎖失敗的線程都會進入睡眠狀態,直到寫鎖釋放時被喚醒。 注意:寫鎖會阻塞其它讀寫鎖。當有一個線程獲得寫鎖在寫時,讀鎖也不能被其它線程獲取;寫者優先於讀者(一旦有寫者,則后續讀者必須等待,喚醒時優先考慮寫者)。適用於讀取數據的頻率遠遠大於寫數據的頻率的場合。
互斥鎖和讀寫鎖的區別:
1)讀寫鎖區分讀者和寫者,而互斥鎖不區分
2)互斥鎖同一時間只允許一個線程訪問該對象,無論讀寫;讀寫鎖同一時間內只允許一個寫者,但是允許多個讀者同時讀對象。
2、Linux的4種鎖機制:
互斥鎖:mutex,用於保證在任何時刻,都只能有一個線程訪問該對象。當獲取鎖操作失敗時,線程會進入睡眠,等待鎖釋放時被喚醒
讀寫鎖:rwlock,分為讀鎖和寫鎖。處於讀操作時,可以允許多個線程同時獲得讀操作。但是同一時刻只能有一個線程可以獲得寫鎖。其它獲取寫鎖失敗的線程都會進入睡眠狀態,直到寫鎖釋放時被喚醒。 注意:寫鎖會阻塞其它讀寫鎖。當有一個線程獲得寫鎖在寫時,讀鎖也不能被其它線程獲取;寫者優先於讀者(一旦有寫者,則后續讀者必須等待,喚醒時優先考慮寫者)。適用於讀取數據的頻率遠遠大於寫數據的頻率的場合。
自旋鎖:spinlock,在任何時刻同樣只能有一個線程訪問對象。但是當獲取鎖操作失敗時,不會進入睡眠,而是會在原地自旋,直到鎖被釋放。這樣節省了線程從睡眠狀態到被喚醒期間的消耗,在加鎖時間短暫的環境下會極大的提高效率。但如果加鎖時間過長,則會非常浪費CPU資源。
RCU:即read-copy-update,在修改數據時,首先需要讀取數據,然后生成一個副本,對副本進行修改。修改完成后,再將老數據update成新的數據。使用RCU時,讀者幾乎不需要同步開銷,既不需要獲得鎖,也不使用原子指令,不會導致鎖競爭,因此就不用考慮死鎖問題了。而對於寫者的同步開銷較大,它需要復制被修改的數據,還必須使用鎖機制同步並行其它寫者的修改操作。在有大量讀操作,少量寫操作的情況下效率非常高。
● 請回答一下進程和線程的區別
參考回答:
1、一個線程只能屬於一個進程,而一個進程可以有多個線程,但至少有一個線程。線程依賴於進程而存在。
2、進程在執行過程中擁有獨立的內存單元,而多個線程共享進程的內存。(資源分配給進程,同一進程的所有線程共享該進程的所有資源。同一進程中的多個線程共享代碼段(代碼和常量),數據段(全局變量和靜態變量),擴展段(堆存儲)。但是每個線程擁有自己的棧段,棧段又叫運行時段,用來存放所有局部變量和臨時變量。)
3、進程是資源分配的最小單位,線程是CPU調度的最小單位。
4、系統開銷: 由於在創建或撤消進程時,系統都要為之分配或回收資源,如內存空間、I/o設備等。因此,操作系統所付出的開銷將顯著地大於在創建或撤消線程時的開銷。類似地,在進行進程切換時,涉及到整個當前進程CPU環境的保存以及新被調度運行的進程的CPU環境的設置。而線程切換只須保存和設置少量寄存器的內容,並不涉及存儲器管理方面的操作。可見,進程切換的開銷也遠大於線程切換的開銷。
5、通信:由於同一進程中的多個線程具有相同的地址空間,致使它們之間的同步和通信的實現,也變得比較容易。進程間通信IPC,線程間可以直接讀寫進程數據段(如全局變量)來進行通信——需要進程同步和互斥手段的輔助,以保證數據的一致性。在有的系統中,線程的切換、同步和通信都無須操作系統內核的干預 。
6、進程編程調試簡單可靠性高,但是創建銷毀開銷大;線程正相反,開銷小,切換速度快,但是編程調試相對復雜。
7、進程間不會相互影響 ;線程一個線程掛掉將導致整個進程掛掉。
8、進程適應於多核、多機分布;線程適用於多核。
● 請你說一說進程狀態轉換圖,動態就緒,靜態就緒,動態阻塞,靜態阻塞
參考回答:
1、進程的五種基本狀態:

1)創建狀態:進程正在被創建
2)就緒狀態:進程被加入到就緒隊列中等待CPU調度運行
3)執行狀態:進程正在被運行
4)等待阻塞狀態:進程因為某種原因,比如等待I/O,等待設備,而暫時不能運行。
5)終止狀態:進程運行完畢
2、交換技術
當多個進程競爭內存資源時,會造成內存資源緊張,並且,如果此時沒有就緒進程,處理機會空閑,I/0速度比處理機速度慢得多,可能出現全部進程阻塞等待I/O。
針對以上問題,提出了兩種解決方法:
1)交換技術:換出一部分進程到外存,騰出內存空間。
2)虛擬存儲技術:每個進程只能裝入一部分程序和數據。
在交換技術上,將內存暫時不能運行的進程,或者暫時不用的數據和程序,換出到外存,來騰出足夠的內存空間,把已經具備運行條件的進程,或進程所需的數據和程序換入到內存。
從而出現了進程的掛起狀態:進程被交換到外存,進程狀態就成為了掛起狀態。
3、活動阻塞,靜止阻塞,活動就緒,靜止就緒
1)活動阻塞:進程在內存,但是由於某種原因被阻塞了。
2)靜止阻塞:進程在外存,同時被某種原因阻塞了。
3)活動就緒:進程在內存,處於就緒狀態,只要給CPU和調度就可以直接運行。
4)靜止就緒:進程在外存,處於就緒狀態,只要調度到內存,給CPU和調度就可以運行。
從而出現了:
活動就緒 —— 靜止就緒 (內存不夠,調到外存)
活動阻塞 —— 靜止阻塞 (內存不夠,調到外存)
執行 —— 靜止就緒 (時間片用完)
● A* a = new A; a->i = 10;在內核中的內存分配上發生了什么?
參考回答:
1、程序內存管理:
一個程序本質上都是由BSS段、data段、text段三個組成的。可以看到一個可執行程序在存儲(沒有調入內存)時分為代碼段、數據區和未初始化數據區三部分。

BSS段(未初始化數據區):通常用來存放程序中未初始化的全局變量和靜態變量的一塊內存區域。BSS段屬於靜態分配,程序結束后靜態變量資源由系統自動釋放。
數據段:存放程序中已初始化的全局變量的一塊內存區域。數據段也屬於靜態內存分配
代碼段:存放程序執行代碼的一塊內存區域。這部分區域的大小在程序運行前就已經確定,並且內存區域屬於只讀。在代碼段中,也有可能包含一些只讀的常數變量
text段和data段在編譯時已經分配了空間,而BSS段並不占用可執行文件的大小,它是由鏈接器來獲取內存的。
bss段(未進行初始化的數據)的內容並不存放在磁盤上的程序文件中。其原因是內核在程序開始運行前將它們設置為0。需要存放在程序文件中的只有正文段和初始化數據段。
data段(已經初始化的數據)則為數據分配空間,數據保存到目標文件中。
數據段包含經過初始化的全局變量以及它們的值。BSS段的大小從可執行文件中得到,然后鏈接器得到這個大小的內存塊,緊跟在數據段的后面。當這個內存進入程序的地址空間后全部清零。包含數據段和BSS段的整個區段此時通常稱為數據區。
可執行程序在運行時又多出兩個區域:棧區和堆區。
棧區:由編譯器自動釋放,存放函數的參數值、局部變量等。每當一個函數被調用時,該函數的返回類型和一些調用的信息被存放到棧中。然后這個被調用的函數再為他的自動變量和臨時變量在棧上分配空間。每調用一個函數一個新的棧就會被使用。棧區是從高地址位向低地址位增長的,是一塊連續的內存區域,最大容量是由系統預先定義好的,申請的棧空間超過這個界限時會提示溢出,用戶能從棧中獲取的空間較小。
堆區:用於動態分配內存,位於BSS和棧中間的地址區域。由程序員申請分配和釋放。堆是從低地址位向高地址位增長,采用鏈式存儲結構。頻繁的 malloc/free造成內存空間的不連續,產生碎片。當申請堆空間時庫函數是按照一定的算法搜索可用的足夠大的空間。因此堆的效率比棧要低的多。
2、A* a = new A; a->i = 10:
1)A *a:a是一個局部變量,類型為指針,故而操作系統在程序棧區開辟4/8字節的空間(0x000m),分配給指針a。
2)new A:通過new動態的在堆區申請類A大小的空間(0x000n)。
3)a = new A:將指針a的內存區域填入棧中類A申請到的地址的地址。即*(0x000m)=0x000n。
4)a->i:先找到指針a的地址0x000m,通過a的值0x000n和i在類a中偏移offset,得到a->i的地址0x000n + offset,進行*(0x000n + offset) = 10的賦值操作,即內存0x000n + offset的值是10。
● 給你一個類,里面有static,virtual,之類的,來說一說這個類的內存分布
參考回答:
1、static修飾符
1)static修飾成員變量
對於非靜態數據成員,每個類對象都有自己的拷貝。而靜態數據成員被當做是類的成員,無論這個類被定義了多少個,靜態數據成員都只有一份拷貝,為該類型的所有對象所共享(包括其派生類)。所以,靜態數據成員的值對每個對象都是一樣的,它的值可以更新。
因為靜態數據成員在全局數據區分配內存,屬於本類的所有對象共享,所以它不屬於特定的類對象,在沒有產生類對象前就可以使用。
2)static修飾成員函數
與普通的成員函數相比,靜態成員函數由於不是與任何的對象相聯系,因此它不具有this指針。從這個意義上來說,它無法訪問屬於類對象的非靜態數據成員,也無法訪問非靜態成員函數,只能調用其他的靜態成員函數。
Static修飾的成員函數,在代碼區分配內存。
2、C++繼承和虛函數
C++多態分為靜態多態和動態多態。靜態多態是通過重載和模板技術實現,在編譯的時候確定。動態多態通過虛函數和繼承關系來實現,執行動態綁定,在運行的時候確定。
動態多態實現有幾個條件:
(1) 虛函數;
(2) 一個基類的指針或引用指向派生類的對象;
基類指針在調用成員函數(虛函數)時,就會去查找該對象的虛函數表。虛函數表的地址在每個對象的首地址。查找該虛函數表中該函數的指針進行調用。
每個對象中保存的只是一個虛函數表的指針,C++內部為每一個類維持一個虛函數表,該類的對象的都指向這同一個虛函數表。
虛函數表中為什么就能准確查找相應的函數指針呢?因為在類設計的時候,虛函數表直接從基類也繼承過來,如果覆蓋了其中的某個虛函數,那么虛函數表的指針就會被替換,因此可以根據指針准確找到該調用哪個函數。
3、virtual修飾符
如果一個類是局部變量則該類數據存儲在棧區,如果一個類是通過new/malloc動態申請的,則該類數據存儲在堆區。
如果該類是virutal繼承而來的子類,則該類的虛函數表指針和該類其他成員一起存儲。虛函數表指針指向只讀數據段中的類虛函數表,虛函數表中存放着一個個函數指針,函數指針指向代碼段中的具體函數。
如果類中成員是virtual屬性,會隱藏父類對應的屬性。

● 請你回答一下軟鏈接和硬鏈接區別
參考回答:
為了解決文件共享問題,Linux引入了軟鏈接和硬鏈接。除了為Linux解決文件共享使用,還帶來了隱藏文件路徑、增加權限安全及節省存儲等好處。若1個inode號對應多個文件名,則為硬鏈接,即硬鏈接就是同一個文件使用了不同的別名,使用ln創建。若文件用戶數據塊中存放的內容是另一個文件的路徑名指向,則該文件是軟連接。軟連接是一個普通文件,有自己獨立的inode,但是其數據塊內容比較特殊。● 請問什么是大端小端以及如何判斷大端小端
參考回答:
大端是指低字節存儲在高地址;小端存儲是指低字節存儲在低地址。我們可以根據聯合體來判斷該系統是大端還是小端。因為聯合體變量總是從低地址存儲。
● 請你回答一下靜態變量什么時候初始化
參考回答:
靜態變量存儲在虛擬地址空間的數據段和bss段,C語言中其在代碼執行之前初始化,屬於編譯期初始化。而C++中由於引入對象,對象生成必須調用構造函數,因此C++規定全局或局部靜態對象當且僅當對象首次用到時進行構造
● 請你說一說用戶態和內核態區別
參考回答:
用戶態和內核態是操作系統的兩種運行級別,兩者最大的區別就是特權級不同。用戶態擁有最低的特權級,內核態擁有較高的特權級。運行在用戶態的程序不能直接訪問操作系統內核數據結構和程序。內核態和用戶態之間的轉換方式主要包括:系統調用,異常和中斷。
● 如何設計server,使得能夠接收多個客戶端的請求
參考回答:
多線程,線程池,io復用
● 死循環+來連接時新建線程的方法效率有點低,怎么改進?
參考回答:
提前創建好一個線程池,用生產者消費者模型,創建一個任務隊列,隊列作為臨界資源,有了新連接,就掛在到任務隊列上,隊列為空所有線程睡眠。改進死循環:使用select epoll這樣的技術
● 怎么喚醒被阻塞的socket線程?
參考回答:
給阻塞時候缺少的資源
● 怎樣確定當前線程是繁忙還是阻塞?
參考回答:
使用ps命令查看
● 請問就緒狀態的進程在等待什么?
參考回答:
被調度使用cpu的運行權
● 請你說一說多線程的同步,鎖的機制
參考回答:
同步的時候用一個互斥量,在訪問共享資源前對互斥量進行加鎖,在訪問完成后釋放互斥量上的鎖。對互斥量進行加鎖以后,任何其他試圖再次對互斥量加鎖的線程將會被阻塞直到當前線程釋放該互斥鎖。如果釋放互斥鎖時有多個線程阻塞,所有在該互斥鎖上的阻塞線程都會變成可運行狀態,第一個變為運行狀態的線程可以對互斥量加鎖,其他線程將會看到互斥鎖依然被鎖住,只能回去再次等待它重新變為可用。在這種方式下,每次只有一個線程可以向前執行
● 兩個進程訪問臨界區資源,會不會出現都獲得自旋鎖的情況?
參考回答:
單核cpu,並且開了搶占可以造成這種情況。
● windows消息機制知道嗎,請說一說
參考回答:
當用戶有操作(鼠標,鍵盤等)時,系統會將這些時間轉化為消息。每個打開的進程系統都為其維護了一個消息隊列,系統會將這些消息放到進程的消息隊列中,而應用程序會循環從消息隊列中取出來消息,完成對應的操作。
● C++的鎖你知道幾種?
參考回答:
鎖包括互斥鎖,條件變量,自旋鎖和讀寫鎖
● 說一說你用到的鎖
參考回答:
生產者消費者問題利用互斥鎖和條件變量可以很容易解決,條件變量這里起到了替代信號量的作用
● 請你說一說死鎖產生的必要條件?
參考回答:
1.互斥條件:一個資源每次只能被一個進程使用。
2.請求與保持條件:一個進程因請求資源而阻塞時,對已獲得的資源保持不放。
3.不剝奪條件:進程已獲得的資源,在末使用完之前,不能強行剝奪。
4.循環等待條件:若干進程之間形成一種頭尾相接的循環等待資源關系。
● 請你說一說什么是線程和進程,多線程和多進程通信方式
參考回答:
1)概念:
進程是對運行時程序的封裝,是系統進行資源調度和分配的的基本單位,實現了操作系統的並發;
線程是進程的子任務,是CPU調度和分派的基本單位,用於保證程序的實時性,實現進程內部的並發;線程是操作系統可識別的最小執行和調度單位。每個線程都獨自占用一個虛擬處理器:獨自的寄存器組,指令計數器和處理器狀態。每個線程完成不同的任務,但是共享同一地址空間(也就是同樣的動態內存,映射文件,目標代碼等等),打開的文件隊列和其他內核資源。
2)進程間通信的方式:
進程間通信主要包括管道、系統IPC(包括消息隊列、信號量、信號、共享內存等)、以及套接字socket。
1、管道:
管道主要包括無名管道和命名管道:管道可用於具有親緣關系的父子進程間的通信,有名管道除了具有管道所具有的功能外,它還允許無親緣關系進程間的通信
普通管道PIPE:
它是半雙工的(即數據只能在一個方向上流動),具有固定的讀端和寫端
它只能用於具有親緣關系的進程之間的通信(也是父子進程或者兄弟進程之間)
它可以看成是一種特殊的文件,對於它的讀寫也可以使用普通的read、write等函數。但是它不是普通的文件,並不屬於其他任何文件系統,並且只存在於內存中。
命名管道FIFO:
FIFO可以在無關的進程之間交換數據
FIFO有路徑名與之相關聯,它以一種特殊設備文件形式存在於文件系統中。
2、消息隊列
消息隊列,是消息的鏈接表,存放在內核中。一個消息隊列由一個標識符(即隊列ID)來標記。消息隊列克服了信號傳遞信息少,管道只能承載無格式字節流以及緩沖區大小受限等特點。具有寫權限得進程可以按照一定得規則向消息隊列中添加新信息,對消息隊列有讀權限得進程則可以從消息隊列中讀取信息。消息隊列是面向記錄的,其中的消息具有特定的格式以及特定的優先級。
消息隊列獨立於發送與接收進程。進程終止時,消息隊列及其內容並不會被刪除。
消息隊列可以實現消息的隨機查詢,消息不一定要以先進先出的次序讀取,也可以按消息的類型讀取。
3、信號量semaphore
信號量(semaphore)與已經介紹過的 IPC 結構不同,它是一個計數器,可以用 來控制多個進程對共享資源的訪問。信號量用於實現進程間的互斥與同步,而不是用於 存儲進程間通信數據。
信號量用於進程間同步,若要在進程間傳遞數據需要結合共享內存。
信號量基於操作系統的PV 操作,程序對信號量的操作都是原子操作。
每次對信號量的PV 操作不僅限於對信號量值加 1 或減 1,而且可以加減任 意正整數。
支持信號量組。
4信號signal
信號是一種比較復雜的通信方式,用於通知接收進程某個事件已經發生。
5共享內存(Shared Memory)
它使得多個進程可以訪問同一塊內存空間,不同進程可以及時看到對方進程中對共享內存中數據得更新。這種方式需要依靠某種同步操作,如互斥鎖和信號量等。
共享內存是最快的一種IPC,因為進程是直接對內存進行存取
因為多個進程可以同時操作,所以需要進行同步
信號量+共享內存通常結合在一起使用,信號量用來同步對共享內存的訪問
6、套接字SOCKET:
socket也是一種進程間通信機制,與其他通信機制不同的是,它可用於不同主機之間的進程通信。
3)線程間通信的方式:
1、臨界區:
通過多線程的串行化來訪問公共資源或一段代碼,速度快,適合控制數據訪問;
2、互斥量 Synchronized/Lock:
采用互斥對象機制,只有擁有互斥對象的線程才有訪問公共資源的權限。因為互斥對象只有一個,所以可以保證公共資源不會被多個線程同時訪問
3、信號量 Semphare:
為控制具有有限數量的用戶資源而設計的,它允許多個線程在同一時刻去訪問同一個資源,但一般需要限制同一時刻訪問此資源的最大線程數目。
4、事件(信號),Wait/Notify:
通過通知操作的方式來保持多線程同步,還可以方便的實現多線程優先級的比較操作。
● 請你說一說內存溢出和內存泄漏
參考回答:
1、內存溢出
指程序申請內存時,沒有足夠的內存供申請者使用。內存溢出就是你要的內存空間超過了系統實際分配給你的空間,此時系統相當於沒法滿足你的需求,就會報內存溢出的錯誤
內存溢出原因:
內存中加載的數據量過於龐大,如一次從數據庫取出過多數據
集合類中有對對象的引用,使用完后未清空,使得不能回收
代碼中存在死循環或循環產生過多重復的對象實體
使用的第三方軟件中的BUG
啟動參數內存值設定的過小
2、內存泄漏
內存泄漏是指由於疏忽或錯誤造成了程序未能釋放掉不再使用的內存的情況。內存泄漏並非指內存在物理上的消失,而是應用程序分配某段內存后,由於設計錯誤,失去了對該段內存的控制,因而造成了內存的浪費。
內存泄漏的分類:
1、堆內存泄漏 (Heap leak)。對內存指的是程序運行中根據需要分配通過malloc,realloc new等從堆中分配的一塊內存,再是完成后必須通過調用對應的 free或者delete 刪掉。如果程序的設計的錯誤導致這部分內存沒有被釋放,那么此后這塊內存將不會被使用,就會產生Heap Leak。
2、系統資源泄露(Resource Leak)。主要指程序使用系統分配的資源比如 Bitmap,handle ,SOCKET等沒有使用相應的函數釋放掉,導致系統資源的浪費,嚴重可導致系統效能降低,系統運行不穩定。
3、沒有將基類的析構函數定義為虛函數。當基類指針指向子類對象時,如果基類的析構函數不是virtual,那么子類的析構函數將不會被調用,子類的資源沒有正確是釋放,因此造成內存泄露。
● 進程和線程的區別,你都使用什么線程模型
參考回答:
1)進程和線程區別
1、一個線程只能屬於一個進程,而一個進程可以有多個線程,但至少有一個線程。線程依賴於進程而存在。
2、進程在執行過程中擁有獨立的內存單元,而多個線程共享進程的內存。(資源分配給進程,同一進程的所有線程共享該進程的所有資源。同一進程中的多個線程共享代碼段(代碼和常量),數據段(全局變量和靜態變量),擴展段(堆存儲)。但是每個線程擁有自己的棧段,棧段又叫運行時段,用來存放所有局部變量和臨時變量。)
3、進程是資源分配的最小單位,線程是CPU調度的最小單位。
4、系統開銷: 由於在創建或撤消進程時,系統都要為之分配或回收資源,如內存空間、I/o設備等。因此,操作系統所付出的開銷將顯著地大於在創建或撤消線程時的開銷。類似地,在進行進程切換時,涉及到整個當前進程CPU環境的保存以及新被調度運行的進程的CPU環境的設置。而線程切換只須保存和設置少量寄存器的內容,並不涉及存儲器管理方面的操作。可見,進程切換的開銷也遠大於線程切換的開銷。
5、通信:由於同一進程中的多個線程具有相同的地址空間,致使它們之間的同步和通信的實現,也變得比較容易。進程間通信IPC,線程間可以直接讀寫進程數據段(如全局變量)來進行通信——需要進程同步和互斥手段的輔助,以保證數據的一致性。在有的系統中,線程的切換、同步和通信都無須操作系統內核的干預 。
6、進程編程調試簡單可靠性高,但是創建銷毀開銷大;線程正相反,開銷小,切換速度快,但是編程調試相對復雜。
7、進程間不會相互影響;線程一個線程掛掉將導致整個進程掛掉。
8、進程適應於多核、多機分布;線程適用於多核。
2、常用線程模型
1、Future模型
該模型通常在使用的時候需要結合Callable接口配合使用。
Future是把結果放在將來獲取,當前主線程並不急於獲取處理結果。允許子線程先進行處理一段時間,處理結束之后就把結果保存下來,當主線程需要使用的時候再向子線程索取。
Callable是類似於Runnable的接口,其中call方法類似於run方法,所不同的是run方法不能拋出受檢異常沒有返回值,而call方法則可以拋出受檢異常並可設置返回值。兩者的方法體都是線程執行體。
2、fork&join模型
該模型包含遞歸思想和回溯思想,遞歸用來拆分任務,回溯用合並結果。可以用來處理一些可以進行拆分的大任務。其主要是把一個大任務逐級拆分為多個子任務,然后分別在子線程中執行,當每個子線程執行結束之后逐級回溯,返回結果進行匯總合並,最終得出想要的結果。
這里模擬一個摘蘋果的場景:有100棵蘋果樹,每棵蘋果樹有10個蘋果,現在要把他們摘下來。為了節約時間,規定每個線程最多只能摘10棵蘋樹以便於節約時間。各個線程摘完之后匯總計算總蘋果樹。
3、actor模型
actor模型屬於一種基於消息傳遞機制並行任務處理思想,它以消息的形式來進行線程間數據傳輸,避免了全局變量的使用,進而避免了數據同步錯誤的隱患。actor在接受到消息之后可以自己進行處理,也可以繼續傳遞(分發)給其它actor進行處理。在使用actor模型的時候需要使用第三方Akka提供的框架。
4、生產者消費者模型
生產者消費者模型都比較熟悉,其核心是使用一個緩存來保存任務。開啟一個/多個線程來生產任務,然后再開啟一個/多個來從緩存中取出任務進行處理。這樣的好處是任務的生成和處理分隔開,生產者不需要處理任務,只負責向生成任務然后保存到緩存。而消費者只需要從緩存中取出任務進行處理。使用的時候可以根據任務的生成情況和處理情況開啟不同的線程來處理。比如,生成的任務速度較快,那么就可以靈活的多開啟幾個消費者線程進行處理,這樣就可以避免任務的處理響應緩慢的問題。
5、master-worker模型
master-worker模型類似於任務分發策略,開啟一個master線程接收任務,然后在master中根據任務的具體情況進行分發給其它worker子線程,然后由子線程處理任務。如需返回結果,則worker處理結束之后把處理結果返回給master。
摘自牛客網!