線程和進程:
線程:是程序執行流的最小單元,是系統獨立調度和分配CPU(獨立運行)的基本單位。
進程:是資源分配的基本單位。一個進程包括多個線程。html
區別:
1.線程與資源分配無關,它屬於某一個進程,並與進程內的其餘線程一塊兒共享進程的資源。
2.每一個進程都有本身一套獨立的資源(數據),供其內的全部線程共享。
3.不管是大小,開銷線程要更「輕量級」
4.一個進程內的線程通訊比進程之間的通訊更快速,有效。(由於共享變量)java
多線程:同一時刻執行多個線程。用瀏覽器一邊下載,一邊聽歌,一邊看視頻,一邊看網頁。。。
多進程:同時執行多個程序。如,同事運行YY,QQ,以及各類瀏覽器。linux
併發和並行:
併發:當有多個線程在操做時,若是系統只有一個CPU,則它根本不可能真正同時進行一個以上的線程,它只能把CPU運行時間劃分紅若干個時間段,再將時間 段分配給各個線程執行,在一個時間段的線程代碼運行時,其它線程處於掛起狀。.這種方式咱們稱之爲併發(Concurrent)。
並行:當系統有一個以上CPU時,則線程的操做有可能非併發。當一個CPU執行一個線程時,另外一個CPU能夠執行另外一個線程,兩個線程互不搶佔CPU資源,能夠同時進行,這種方式咱們稱之爲並行(Parallel)。
強烈注意:多核,多cup,多機是不一樣的概念。編程
一、繼承Thread類建立線程
二、實現Runnable接口建立線程
三、實現Callable接口經過FutureTask包裝器來建立Thread線程
四、使用ExecutorService、Callable、Future實現有返回結果的線程
參考:Executor框架使用
Executor框架使用2小程序
(1)管道(Pipe):管道可用於具備親緣關係進程間的通訊,容許一個進程和另外一個與它有共同祖先的進程之間進行通訊。
(2)命名管道(named pipe):命名管道克服了管道沒有名字的限制,所以,除具備管道所具備的功能外,它還容許無親緣關 系 進程間的通訊。命名管道在文件系統中有對應的文件名。命名管道經過命令mkfifo或系統調用mkfifo來建立。
(3)信號(Signal):信號是比較複雜的通訊方式,用於通知接受進程有某種事件發生,除了用於進程間通訊外,進程還能夠發送 信號給進程自己;linux除了支持Unix早期信號語義函數sigal外,還支持語義符合Posix.1標準的信號函數sigaction(實際上,該函數是基於BSD的,BSD爲了實現可靠信號機制,又可以統一對外接口,用sigaction函數從新實現了signal函數)。
(4)消息(Message)隊列:消息隊列是消息的連接表,包括Posix消息隊列system V消息隊列。有足夠權限的進程能夠向隊列中添加消息,被賦予讀權限的進程則能夠讀走隊列中的消息。消息隊列克服了信號承載信息量少,管道只能承載無格式字節流以及緩衝區大小受限等缺
(5)共享內存:使得多個進程能夠訪問同一塊內存空間,是最快的可用IPC形式。是針對其餘通訊機制運行效率較低而設計的。每每與其它通訊機制,如信號量結合使用,來達到進程間的同步及互斥。
(6)內存映射(mapped memory):內存映射容許任何多個進程間通訊,每個使用該機制的進程經過把一個共享的文件映射到本身的進程地址空間來實現它。
(7)信號量(semaphore):主要做爲進程間以及同一進程不一樣線程之間的同步手段。
(8)套接口(Socket):更爲通常的進程間通訊機制,可用於不一樣機器之間的進程間通訊。起初是由Unix系統的BSD分支開發出來的,但如今通常能夠移植到其它類Unix系統上:Linux和System V的變種都支持套接字。瀏覽器
而在java中咱們實現多線程間通訊則主要採用"共享變量"和"管道流"這兩種方法服務器
線程是稀缺資源,若是被無限制的建立,不只會消耗系統資源,還會下降系統的穩定性,合理的使用線程池對線程進行統一分配、調優和監控,有如下好處:
一、下降資源消耗;
二、提升響應速度;
三、提升線程的可管理性。網絡
Executors是java線程池的工廠類,經過它能夠快速初始化一個符合業務需求的線程池。
newFiexedThreadPool
newCachedThreadPool
newSingleThreadExecutor
newScheduledThreadPool多線程
當提交一個新任務到線程池時,線程池的處理流程以下。
1)線程池判斷核心線程池裏的線程是否都在執行任務。若是不是,則建立一個新的工做
線程來執行任務。若是核心線程池裏的線程都在執行任務,則進入下個流程。
2)線程池判斷工做隊列是否已經滿。若是工做隊列沒有滿,則將新提交的任務存儲在這
個工做隊列裏。若是工做隊列滿了,則進入下個流程。
3)線程池判斷線程池的線程是否都處於工做狀態。若是沒有,則建立一個新的工做線程
來執行任務。若是已經滿了,則交給飽和策略來處理這個任務。併發
要配置一個線程池是比較複雜的,尤爲是對於線程池的原理不是很清楚的狀況下,頗有可能配置的線程池不是較優的,所以在Executors類裏面提供了一些靜態工廠,生成一些經常使用的線程池。
1.newCachedThreadPool:
底層:返回ThreadPoolExecutor實例,corePoolSize爲0;maximumPoolSize爲Integer.MAX_VALUE;keepAliveTime爲60L;unit爲TimeUnit.SECONDS;workQueue爲SynchronousQueue(同步隊列)
通俗:當有新任務到來,則插入到SynchronousQueue中,因爲SynchronousQueue是同步隊列,所以會在池中尋找可用線程來執行,如有能夠線程則執行,若沒有可用線程則建立一個線程來執行該任務;若池中線程空閒時間超過指定大小,則該線程會被銷燬。
適用:執行不少短時間異步的小程序或者負載較輕的服務器
2.newFixedThreadPool:
底層:返回ThreadPoolExecutor實例,接收參數爲所設定線程數量nThread,corePoolSize爲nThread,maximumPoolSize爲nThread;keepAliveTime爲0L(不限時);unit爲:TimeUnit.MILLISECONDS;WorkQueue爲:new LinkedBlockingQueue
通俗:建立可容納固定數量線程的池子,每隔線程的存活時間是無限的,當池子滿了就不在添加線程了;若是池中的全部線程均在繁忙狀態,對於新任務會進入阻塞隊列中(無界的阻塞隊列),可是,在線程池空閒時,即線程池中沒有可運行任務時,它不會釋放工做線程,還會佔用必定的系統資源。
適用:執行長期的任務,性能好不少
3.newSingleThreadExecutor:
底層:FinalizableDelegatedExecutorService包裝的ThreadPoolExecutor實例,corePoolSize爲1;maximumPoolSize爲1;keepAliveTime爲0L;unit爲:TimeUnit.MILLISECONDS;workQueue爲:new LinkedBlockingQueue
通俗:建立只有一個線程的線程池,且線程的存活時間是無限的;當該線程正繁忙時,對於新任務會進入阻塞隊列中(無界的阻塞隊列)
適用:一個任務一個任務執行的場景
4.NewScheduledThreadPool:
底層:建立ScheduledThreadPoolExecutor實例,corePoolSize爲傳遞來的參數,maximumPoolSize爲Integer.MAX_VALUE;keepAliveTime爲0;unit爲:TimeUnit.NANOSECONDS;workQueue爲:new DelayedWorkQueue() 一個按超時時間升序排序的隊列
通俗:建立一個固定大小的線程池,線程池內線程存活時間無限制,線程池能夠支持定時及週期性任務執行,若是全部線程均處於繁忙狀態,對於新任務會進入DelayedWorkQueue隊列中,這是一種按照超時時間排序的隊列結構
適用:週期性執行任務的場景
生命週期:
(1)新建狀態——(2)就緒狀態—((4)阻塞狀態)—(3)運行狀態——(5)死亡狀態
詳解:
(1)New:建立線程對象後,該線程處於新建狀態,此時它不能運行,和其餘Java對象同樣,僅僅有Java虛擬機爲其分配了內存,沒有表現出任何線程的動態特徵;
(2)Runnable:線程對象調用了start()方法後,該線程就進入了就緒狀態(也稱可運行狀態)。處於就緒狀態的線程位於可運行池中,此時它只是具有了運行的條件,可否得到CPU的使用權開始運行,還須要等待系統的調度;
(3)Runing:處於就緒狀態的線程得到了CPU使用權,開始執行run()方法中的線程執行體,則線程處於運行狀態。當一個線程啓動後,它不能一直處於運行狀態(除非它的線程執行體足夠短,瞬間結束),當使用完系統分配的時間後,系統就會剝脫該線程佔用的CPU資源,讓其餘線程得到執行的機會。只有處於就緒狀態的線程纔可能轉換到運行狀態。
(4)Blocked:一個正在執行的線程在某些特殊狀況下,如執行耗時的輸入/輸出操做時,會放棄CPU的使用權,進入阻塞狀態。線程進入阻塞狀態後,就不能進入排隊隊列。只有當引用阻塞的緣由,被消除後,線程才能夠進入就緒狀態。
——當線程試圖獲取某個對象的同步鎖時,若是該鎖被其餘線程所持有,則當前線程進入阻塞狀態,若是想從阻塞狀態進入就緒狀態必須得獲取到其餘線程所持有的鎖。
——當線程調用了一個阻塞式的IO方法時,該線程就會進入阻塞狀態,若是想進入就緒狀態就必需要等到這個阻塞的IO方法返回。
——當線程調用了某個對象的wait()方法時,也會使線程進入阻塞狀態,notify()方法喚醒。
——調用了Thread的sleep(long millis)。線程睡眠時間到了會自動進入阻塞狀態。
——一個線程調用了另外一個線程的join()方法時,當前線程進入阻塞狀態。等新加入的線程運行結束後會結束阻塞狀態,進入就緒狀態。
線程從阻塞狀態只能進入就緒狀態,而不能直接進入運行狀態,即結束阻塞的線程須要從新進入可運行池中,等待系統的調度。
(5)Terminated:線程的run()方法正常執行完畢或者線程拋出一個未捕獲的異常(Exception)、錯誤(Error),線程就進入死亡狀態。一旦進入死亡狀態,線程將再也不擁有運行的資格,也不能轉換爲其餘狀態。