一、進程相關概念:
1、程序是一個靜態(tài)的概念,進程是執(zhí)行起來的程序,是一個動態(tài)的概念。線程是進程的一部分,一個進程可以有一個或多個線程 2、進程和線程最根本的區(qū)別在于:進程是資源分配的單位,線程是調度和執(zhí)行的單位。線程可以看成是輕量級的進程,線程之間切換開銷很小 3、多進程:在操作系統(tǒng)中同時運行多個任務(程序) 4、多線程:在同一應用程序中有多個順序流同時執(zhí)行 5、每個進程都有獨立的代碼和數(shù)據(jù)空間(稱為:進程上下文),進程間的切換會有較大的開銷 6、系統(tǒng)會為每個進程分配不同的內存區(qū)域,但是不會為線程分配內存。計算機軟硬件資源的分配與線程無關,線程只能共享它所屬進程的資源
二、Java中實現(xiàn)多線程的方式(三種):
1、通過繼承Thread類,重寫run方法,創(chuàng)建實例對象,調用start()方法來實現(xiàn)。
需要注意的是:調用start()方法后,并不是立即執(zhí)行多線程代碼,而是使得該線程變?yōu)榭蛇\行狀態(tài)(Runnable),具體什么時候執(zhí)行多線程代碼由操作系統(tǒng)決定
這種方法的缺點是:如果類已經(jīng)繼承了一個類,則無法再繼承Thread類。因為Java是單繼承
2、實現(xiàn)Runnable接口,并實現(xiàn)該接口的run()方法【一般推薦使用此方法】。具體步驟如下:
?、僮远x類并實現(xiàn)Runnable接口,實現(xiàn)run方法
?、趧?chuàng)建Thread對象,用實現(xiàn)Runnable接口的對象作為參數(shù)實例化該Thread對象。如 Thread thread1 = new Thread(new TestThread2());
③調用Thread的start方法
這種方式也是開發(fā)中更多使用的方法。因為Thread類定義了多種可以被派生類使用或重寫,但是只有run方法是必須被重寫的,在run方法中實現(xiàn)這個線程的主要功能
3、實現(xiàn)Callable接口,重寫call方法。Callable接口與Runnable 接口類似,功能比runnable更強大,主要有以下三點:
?、貱allable可以提供返回值,Runnable沒有
?、贑allable中的call方法可以拋出異常
三、線程狀態(tài)和生命周期
1、線程有 5 種狀態(tài):新生,就緒,運行,死亡,阻塞。線程生命周期圖如下【好好理解,基本包含了線程整個生命周期的知識】:
終止線程的方法:一般不使用JDK提供的stop/destory方法,他們本身也被棄用。通常使用一個boolean的標記變量,當這個變量置位false時,終止線程的運行
暫停線程的方法:使用sleep方法和yield方法。這兩種方法的區(qū)別:sleep方法是讓正在運行的線程進入阻塞狀態(tài),直到休眠期滿了,才進入就緒狀態(tài)。yield方法則是讓線程直接進入就緒狀態(tài)
四、說說你對線程池的理解
1、線程池簡單來說就是一句話,用來對線程進行一個集中統(tǒng)一的管理,以此來減少系統(tǒng)資源的消耗。
因為創(chuàng)建線程是非常耗時的, 多線程運行時間,系統(tǒng)不斷的啟動和關閉新線程,成本非常高,會過渡消耗系統(tǒng)資源,以及過渡切換線程的危險,從而可能導致系統(tǒng)資源的崩潰。
2、線程池的優(yōu)勢:
?、俳档拖到y(tǒng)資源消耗,提高系統(tǒng)響應速度。通過重用已存在的線程,一個線程可執(zhí)行多個任務,降低線程創(chuàng)建和銷毀造成的消耗;
②方便線程并發(fā)數(shù)的管控。因為線程若是無限制的創(chuàng)建,可能會導致內存占用過多而產(chǎn)生OOM(內存使用過大),并且會造成cpu過度切換
?、厶峁└鼜姶蟮墓δ?,延時定時線程池
3、線程池的參數(shù)有哪些:
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) { this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, Executors.defaultThreadFactory(), defaultHandler); }
1、corePoolSize(線程池基本大?。寒斚蚓€程池提交一個任務時,若線程池已創(chuàng)建的線程數(shù)小于corePoolSize,即便此時存在空閑線程,也會通過創(chuàng)建一個新線程來執(zhí)行該任務,直到已創(chuàng)建的線程數(shù)大于或等于corePoolSize時,(除了利用提交新任務來創(chuàng)建和啟動線程(按需構造),也可以通過 prestartCoreThread() 或 prestartAllCoreThreads() 方法來提前啟動線程池中的基本線程。)
2、maximumPoolSize(線程池最大大?。壕€程池所允許的最大線程個數(shù)。當隊列滿了,且已創(chuàng)建的線程數(shù)小于maximumPoolSize,則線程池會創(chuàng)建新的線程來執(zhí)行任務。另外,對于無界隊列,可忽略該參數(shù)。
3、keepAliveTime(線程存活保持時間)當線程池中線程數(shù)大于核心線程數(shù)時,線程的空閑時間如果超過線程存活時間,那么這個線程就會被銷毀,直到線程池中的線程數(shù)小于等于核心線程數(shù)。
4、workQueue(任務隊列):用于傳輸和保存等待執(zhí)行任務的阻塞隊列。
5、threadFactory(線程工廠):用于創(chuàng)建新線程。threadFactory創(chuàng)建的線程也是采用new Thread()方式,threadFactory創(chuàng)建的線程名都具有統(tǒng)一的風格:pool-m-thread-n(m為線程池的編號,n為線程池內的線程編號)。
6、handler(線程飽和策略):當線程池和隊列都滿了,再加入線程會執(zhí)行此策略。
4、線程池流程:
5、線程池為什么需要使用(阻塞)隊列?
1、因為線程若是無限制的創(chuàng)建,可能會導致內存占用過多而產(chǎn)生OOM,并且會造成cpu過度切換。
2、創(chuàng)建線程池的消耗較高。
3、線程池創(chuàng)建線程需要獲取mainlock這個全局鎖,影響并發(fā)效率,阻塞隊列可以很好的緩沖。
6、Java提供了四個線程池的實現(xiàn)類:
?、?newSingleThreadExecutor:創(chuàng)建一個單線程的線程池,它只會用唯一的工作線程來執(zhí)行任務,也就是相當于單線程串行執(zhí)行所有任務。如果這個線程因為異常結束了,會有一個新的線程來替代它
?、?newFixedThreadPool:創(chuàng)建一個定長的線程池,可控制線程的最大并發(fā)量,超出的線程會在隊列中等待。使用這個線程時,要預先估算出線程的數(shù)量
?、?nbsp;newCachedThreadPool:用來創(chuàng)建一個可緩存的線程池,適用于負載較輕的場景,執(zhí)行短期異步任務。(可以使得任務快速得到執(zhí)行,因為任務時間執(zhí)行短,可以很快結束,也不會造成cpu過度切換)
④ newScheduledThreadPool:創(chuàng)建一個定長線程池,適用于執(zhí)行定時或者周期性任務的需求