國內(nèi)免費二級域名網(wǎng)站做電商如何起步
定義
1、進(jìn)程:進(jìn)程是一個具有獨立功能的程序關(guān)于某個數(shù)據(jù)集合的以此運行活動。 是系統(tǒng)進(jìn)行資源分配和調(diào)度的獨立單位,也是基本的執(zhí)行單元。是一個動態(tài)的概念,是一個活動的實體。它不只是程序的代碼,還包括當(dāng)前的活動。
進(jìn)程結(jié)構(gòu)特征: 由程序、數(shù)據(jù)和進(jìn)程控制塊三部分組成。具有 獨立性、并發(fā)性、異步性和動態(tài)性的特點。
(1)、進(jìn)程的概念主要有兩點:
第一,進(jìn)程是一個實體。每一個進(jìn)程都有它自己的地址空間,一般情況下,包括
文本區(qū)域(text region)--存儲處理器執(zhí)行的代碼,
數(shù)據(jù)區(qū)域(data region)--存儲程序執(zhí)行期間的一些數(shù)據(jù)變量,
堆棧(stack region)--存儲動態(tài)分配的內(nèi)存和本地變量及指令。
第二:進(jìn)程是一個“執(zhí)行中的程序”。程序是一個沒有生命的實體,只有在運行時處理器才會賦予它生命,才能成為一個活動的實體,我們稱其為“進(jìn)程”。
每一個進(jìn)程都會有一個獨一無二的編號,被稱為進(jìn)程標(biāo)識碼,簡稱PID(Process,identifier),它是一個取值為1-32768.但是init是一個特殊的進(jìn)程。所謂的init進(jìn)程,是一個內(nèi)核啟動的用戶級進(jìn)程,也是系統(tǒng)上運行的所有其他進(jìn)程的父進(jìn)程,他會觀察子進(jìn)程,并在需要的時候啟動,停止,重新啟動它們,init進(jìn)程主要完成系統(tǒng)各項的配置。linux系統(tǒng)中,init從根文件夾系統(tǒng)目錄里的/etc/inittab文件里獲取信息。是所有進(jìn)程的發(fā)起者和控制者,內(nèi)核啟動后,便由init進(jìn)程來進(jìn)行各項配置。
(2)、進(jìn)程的三種狀態(tài):
就緒(Ready)狀態(tài):當(dāng)進(jìn)程分配到除CPU以外的必要資源后,只要再獲得CPU,便可以立即執(zhí)行,進(jìn)程這時的狀態(tài)為就緒狀態(tài)。在一個系統(tǒng)中處于就緒狀態(tài)的進(jìn)程可能有多個,通常將它們排成一個隊列,稱為就緒隊列。
阻塞(Blocked)狀態(tài):正在執(zhí)行的進(jìn)程由于發(fā)生某事件或接受某消息無法繼續(xù)執(zhí)行時,便放棄處理機(jī)而處于暫停狀態(tài),也即進(jìn)程的執(zhí)行收到阻塞,把這種暫停狀態(tài)稱為阻塞狀態(tài),有時也稱為等待狀態(tài)和封鎖狀態(tài)。通常使進(jìn)程處于阻塞的原因有:請求I/O,申請緩沖空間。也會產(chǎn)生一個相應(yīng)的阻塞隊列。
運行(Running)狀態(tài):進(jìn)程已獲得CPU,其程序正在執(zhí)行。在單處理機(jī)系統(tǒng)中,只有一個進(jìn)程處于執(zhí)行狀態(tài),在多處理機(jī)系統(tǒng)中,則有多個進(jìn)程處于執(zhí)行狀態(tài);
其關(guān)系如下圖所示:
2、線程:線程是進(jìn)程中的執(zhí)行運算的最小單位,是進(jìn)程中的一個實體,是被系統(tǒng)獨立調(diào)度和分派的基本單位,線程自己不擁有系統(tǒng)資源,只擁有一點在運行中必不可少的資源( 程序計數(shù)器,一組寄存器和棧),但它可與同屬一個進(jìn)程的其他線程 共享進(jìn)程所擁有的全部資源。
線程優(yōu)點:
- (1)易于調(diào)度。
- (2)提高并發(fā)性。通過線程可方便有效地實現(xiàn)并發(fā)性。進(jìn)程可創(chuàng)建多個線程來執(zhí)行同一個程序的不同部分。
- (3)開銷少。創(chuàng)建線程比創(chuàng)建進(jìn)程要快,所需開銷少,占用的資源也少;
- (4)充分發(fā)揮多處理器的功能。通過創(chuàng)建多線程進(jìn)程,每個線程在一個處理器上運行,從而實現(xiàn)應(yīng)用程序的并發(fā)性,使每個處理器都得到充分的運行。
二、進(jìn)程與線程的區(qū)別
(1)調(diào)度:線程作為處理器調(diào)度和分配的基本單位,而進(jìn)程是作為擁有資源的基本單位
(2)并發(fā)性:不僅進(jìn)程之間可以并發(fā)執(zhí)行,同一個進(jìn)程的多個線程之間也可以并發(fā)執(zhí)行
(3)擁有資源:進(jìn)程是擁有資源的一個獨立單位,有自己獨立的地址空間;線程不擁有系統(tǒng)資源,但可以訪問隸屬于進(jìn)程的資源,共享進(jìn)程的地址空間.
(4)系統(tǒng)開銷:在創(chuàng)建或撤消進(jìn)程時,由于系統(tǒng)都要為之分配和回收資源,導(dǎo)致系統(tǒng)的開銷明顯大于創(chuàng)建或撤消線程時的開銷。
三、進(jìn)程和線程的關(guān)系
(1)二者均可并發(fā)執(zhí)行.
(2)線程是指進(jìn)程內(nèi)的一個執(zhí)行單元,也是進(jìn)程內(nèi)的可調(diào)度實體。一個程序至少有一個進(jìn)程,一個進(jìn)程至少有一個線程,一個線程只屬于一個進(jìn)程.
(3)資源分配給進(jìn)程,同一進(jìn)程的所有線程共享該進(jìn)程的所有資源。
(4)處理機(jī)分給線程,即真正在處理機(jī)上運行的是線程。
(5)線程在執(zhí)行過程中,需要協(xié)作同步。不同進(jìn)程的線程間要利用消息通信的辦法實現(xiàn)同步。線程是指進(jìn)程內(nèi)的一個執(zhí)行單元,也是進(jìn)程內(nèi)的可調(diào)度實體.進(jìn)程和線程的主要差別在于它們是不同的操作系統(tǒng)資源管理方式。 進(jìn)程有獨立的地址空間,一個進(jìn)程崩潰后,在保護(hù)模式下不會對其它進(jìn)程產(chǎn)生影響。而線程只是一個進(jìn)程中的不同執(zhí)行路徑,線程有自己的堆棧和局部變量,但線程之間沒有單獨的地址空間, 一個線程死掉就等于整個進(jìn)程死掉,所以多進(jìn)程的程序要比多線程的程序健壯,但在進(jìn)程切換時,耗費資源較大,效率要差一些。但對于一些要求同時進(jìn)行并且又要共享某些變量的并發(fā)操作,只能用線程,不能用進(jìn)程。
四、進(jìn)程間通信的方式
(1)管道(pipe)及有名管道(named pipe):管道可用于具有親緣關(guān)系的父子進(jìn)程間的通信,有名管道除了具有管道所具有的功能外,它還允許無親緣關(guān)系進(jìn)程間的通信。
(2)信號(signal):信號是在軟件層次上對中斷機(jī)制的一種模擬,它是比較復(fù)雜的通信方式,用于通知進(jìn)程有某事件發(fā)生,一個進(jìn)程收到一個信號與處理器收到一個中斷請求效果上可以說是一致的。
(3)消息隊列(message queue):消息隊列是消息的鏈接表,它克服了上兩種通信方式中信號量有限的缺點,具有寫權(quán)限得進(jìn)程可以按照一定得規(guī)則向消息隊列中添加新信息;對消息隊列有讀權(quán)限的進(jìn)程則可以從消息隊列中讀取信息。
(4)共享內(nèi)存(shared memory):可以說這是最有用的進(jìn)程間通信方式。它使得多個進(jìn)程可以訪問同一塊內(nèi)存空間,不同進(jìn)程可以及時看到對方進(jìn)程中共享內(nèi)存中數(shù)據(jù)的更新。這種方式需要依靠某種同步操作,如互斥鎖和信號量等。
(5)信號量(semaphore):主要作為進(jìn)程之間及同一種進(jìn)程的不同線程之間的同步和互斥手段。
(6)套接字(socket):這是一種更為一般的進(jìn)程間通信機(jī)制,它可用于網(wǎng)絡(luò)中不同機(jī)器之間的進(jìn)程間通信,應(yīng)用非常廣泛。
多線程的優(yōu)缺點
優(yōu)點
- 能適當(dāng)提高程序的執(zhí)行效率
- 能適當(dāng)提高資源的利用率(CPU,內(nèi)存)
- 線程上的任務(wù)執(zhí)行完成后,線程會自動銷毀
缺點
- 開啟線程需要占用一定的內(nèi)存空間(默認(rèn)情況下,每一個線程都占 512 KB)
- 如果開啟大量的線程,會占用大量的內(nèi)存空間,降低程序的性能
- 線程越多,CPU 在調(diào)用線程上的開銷就越大
- 程序設(shè)計更加復(fù)雜,比如線程間的通信、多線程的數(shù)據(jù)共享
多線程使用場景:
場景1:當(dāng)某個接口響應(yīng)速度很慢的時候,可以使用多線程提升響應(yīng)速度。前提是這個接口獲取信息的邏輯互相獨立,比如首頁接口,需要獲取列表A,列表B,列表C等,而列表ABC三者之間互相獨立(也就是不需要獲取到A,就能獲取到B),互相之間沒有關(guān)系。這種情況就可以使用多線程去優(yōu)化,總耗時為獲取3個列表當(dāng)中耗時最長的那個。
場景2:多線程分批次處理集合數(shù)據(jù),不處理重復(fù)的數(shù)據(jù)。比如有一張學(xué)生表,數(shù)據(jù)量很大,你需要根據(jù)表當(dāng)中的姓名和身份證號這兩個字段去調(diào)用外部接口(外部接口一次只能校驗一條數(shù)據(jù)),校驗之后還需要更新這張表。這個時候可以使用多線程分批次處理,大大提高效率。
public class TestApp {//配置需要同時開啟多少個線程進(jìn)行處理private final int threadNum = 10;/*** @param list 要處理的集合數(shù)據(jù),如果查詢較慢,可以多線程分批次查詢?nèi)缓髤R總在一塊*/public void handleData(List<User> list) {int size = list.size();if (size == 0 || list == null) {return;}ExecutorService executorService = Executors.newFixedThreadPool(threadNum);List<Future<List<User>>> futures = new ArrayList<Future<List<User>>>(size);for (int i = 0; i < threadNum; i++) {//將數(shù)據(jù)分成threadNum份,線程同時執(zhí)行int from = size / threadNum * i;int to = size / threadNum * (i + 1);if (i == threadNum - 1) {to = size;}List<User> subList = list.subList(from, to);Callable<List<User>> task = new Callable<List<User>>() {@Overridepublic List<User> call() {List<User> list1 = new ArrayList<>();//對每個線程(線程中的每份數(shù)據(jù))的邏輯操作for (User user : subList) {//調(diào)用外部接口Boolean res = checkNameAndIdCard(user.getName, user.getIdCard);user.setRes(res);list1.add(user);}return list1;}};//添加線程到隊列futures.add(executorService.submit(task));}//多線程處理后的集合匯總到allList<User> all = new ArrayList<>();for (int i = 0; i < futures.size(); i++) {try {List<User> list1 = futures.get(i).get();all.addAll(list1);} catch (Exception e) {e.printStackTrace();}}//批量更新數(shù)據(jù)庫executorService.shutdown();}/*** 模擬外部接口*/public Boolean checkNameAndIdCard(String name, String idCard) {return true;}}@Data
class User {private Integer id;private String name;private String idCard;private String res;
}
整體流程:
先把要處理的集合從數(shù)據(jù)庫全部撈出來
根據(jù)要開的線程數(shù)量對集合進(jìn)行均分
開多線程對每個集合進(jìn)行處理,處理后返回結(jié)果
Future.get()會造成主線程阻塞,也就是當(dāng)所有future都得到結(jié)果后主線程才能繼續(xù)執(zhí)行下去
場景3:做異步。比如頁面上需要導(dǎo)出excel文件,由于業(yè)務(wù)要求,需要導(dǎo)出全部數(shù)據(jù),導(dǎo)出全部數(shù)據(jù)大概需要10分鐘左右,那如果使用同步的方式,用戶需要在這個導(dǎo)出頁面等待10分鐘,不能做其它操作,這樣肯定是不行的。那么可以采用異步,用戶點擊導(dǎo)出,導(dǎo)出接口主線程往數(shù)據(jù)庫當(dāng)中插入一條導(dǎo)出記錄,開個子線程獲取數(shù)據(jù),寫入Excel文件,完成之后更新導(dǎo)出記錄,當(dāng)中,然后主線程直接給用戶返回。這樣用戶點擊導(dǎo)出會生成一個導(dǎo)出記錄信息,不用在這里等待,等導(dǎo)出完成,之后可以在導(dǎo)出記錄當(dāng)中進(jìn)行下載。代碼就不貼了。
場景4:監(jiān)聽線程,如果某個線程執(zhí)行時間過長(可能死循環(huán)了),超過了自定義的時間,就把該線程干掉,釋放cpu資源
情況1:開一個線程去執(zhí)行這個任務(wù)
public class MainSingle {public static final ExecutorService pool = Executors.newFixedThreadPool(10);public static void main(String[] args) throws Exception {Runnable runnable = new Runnable() {@Overridepublic void run() {System.out.println(Thread.currentThread().getName() + "進(jìn)來了" + this.hashCode());try {Thread.sleep(7000);} catch (InterruptedException e) {}}};FutureTask futureTask = new FutureTask<>(runnable,null);pool.submit(futureTask);long start = System.currentTimeMillis();// 判斷是否完成,如果沒完成就是一直循環(huán)判斷while (!futureTask.isDone()) {long now = System.currentTimeMillis();if ((now - start) >= 6000) {//超時時間3000毫秒futureTask.cancel(true);System.out.println("線程超時了,終止");}}pool.shutdown();}}
情況2:開多個線程,哪個線程死循環(huán),就關(guān)閉哪一個線程,不影響其它線程
知識來源:
【23版面試突擊】進(jìn)程和線程的區(qū)別,使用線程真的能節(jié)省時間?_嗶哩嗶哩_bilibili
操作系統(tǒng):進(jìn)程與線程之間的區(qū)別及聯(lián)系 - 知乎
多線程使用場景_多線程的應(yīng)用場景_木偶亽~的博客-CSDN博客