一、線程
Thread中的方法解釋
1.join()
void join():等待線程終止
void join(long millis):等待該線程終止的最長等待時間是millis毫秒
void join(long millis, int nanos):等待該線程結束的最長等待時間是millis毫秒+nanos納秒
2.sleep()方法
void sleep(long millis):在指定的毫秒數內讓正在執行的線程休眠,此操作受到系統計時器和調度程序精度和準確性的影響。
void sleep(long millis, int nanos)與join類似
sleep(long)使當前進程進入停滯狀態,所以sleep()的線程在指定時間內不會被執行。
sleep(long)是不會釋放鎖的
3.yield()方法
public static void yield()暫停當前正在執行的線程對象,使其進入不可運行狀態,這段時間的長短是由程序設定的,yield方法使當前線程讓出CPU的占有權,但是讓出的時間是不可設定的。并執行其他線程
只會提供相同或者更高優先級的線程運行,不推薦使用
4 wait(): wait()是Object類中的方法,而sleep()是Thread類提供的方法
sleep沒有釋放鎖,使得線程仍然可以同步控制,sleep不會讓出系統資源
而wait是進入線程池中等待,讓出系統資源。
線程的簡單實例:
現在有T1、T2、T3三個線程,你怎樣保證T2在T1執行完后執行,T3在T2執行完后執行?
答:線程類Thread中提供了join()方法,該方法的意義是等待線程執行完畢的意思,因此只需要調用join()方法即可,具體代碼如下:
public class ThreadTest {
? ? public static void main(String [] args){
? ? ? ? method01();
? ? }
? ? private static void method01() {
? ? ? ? final Thread t1 = new Thread(new Runnable() {
? ? ? ? ? ? @Override
? ? ? ? ? ? public void run() {
? ? ? ? ? ? ? ? System.out.println("t1 is Running");
? ? ? ? ? ? }
? ? ? ? });
? ? ? ? final Thread t2 = new Thread(new Runnable() {
? ? ? ? ? ? @Override
? ? ? ? ? ? public void run() {
? ? ? ? ? ? ? ? try {
? ? ? ? ? ? ? ? ? ? t1.join();
? ? ? ? ? ? ? ? } catch (InterruptedException e) {
? ? ? ? ? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? System.out.println("t2 is Running");
? ? ? ? ? ? }
? ? ? ? });
? ? ? ? Thread t3 = new Thread(new Runnable() {
? ? ? ? ? ? @Override
? ? ? ? ? ? public void run() {
? ? ? ? ? ? ? ? try {
? ? ? ? ? ? ? ? ? ? t2.join();
? ? ? ? ? ? ? ? } catch (InterruptedException e) {
? ? ? ? ? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? System.out.println("t3 is Running");
? ? ? ? ? ? }
? ? ? ? });
? ? ? ? t1.start();
? ? ? ? t2.start();
? ? ? ? t3.start();
? ? }
}
二、線程池
1.使用線程池的原因和好處
原因:
1)線程的創建和銷毀都需要時間,當有大量的線程創建和銷毀時,那么這些時間的消耗比較明顯,導致應用性能的下降。
2)大量的線程創建,執行和銷毀非常的消耗CPU和內存,這樣將直接影響系統的吞吐量,導致性能的急劇下降,如果內存占用較多甚至會造成OOM
3)大量的線程的創建很容易導致GC頻繁的執行,進而產生內存抖動的現象,進而造成界面卡頓。
好處
1)減少在創建和銷毀線程上所花的時間以及系統的開銷
2)如果不使用線程池,有可能造成系統創建大量的線程而導致消耗完系統內存以及“過度切換”
2.線程池的使用場景
1)在項目中需要頻繁的開啟線程,需要多線程去處理不同的任務
2)需要監控線程的運行狀態
3.線程池遵循的運行規則
1)如果線程池中的數量為達到核心線程的數量,則直接啟動一個核心線程來執行任務
2)如果線程池的數量已經達到或者超過核心線程的數量,則任務會被插入到任務隊列進行等待。
3)如果(2)中的任務無法插入到任務隊列中,由于任務隊列已滿,這時候如果線程數量未達到線程池規定的最大值,則會啟動一個非核心線程來執行任務。
4)如果(3)中線程數量已經達到了線程池最大值,則會拒絕執行此任務,ThreadPooExector會調用RejectedExecutionHandler的rejectedExection方法通知調用者。
4.ThreadPoolExecutor
ThreadPoolExecutor :線程池,它實現了ExecutorService接口,并封裝了一系列的api是的它具有線程池的特性,其中包括工作隊列,核心線程數以及最大線程數等等。
線程池的種類:
1)newFixedThreadPool作用
返回一個固定線程數的線程池,該線程池中的線程數量始終保持不變,既不會再創建新的線程,也不會銷毀已經創建好的線程,自始至終都是那幾個固定線程在工作,因此該線程池可以控制線程的最大并發數;
例子如果有一個新的任務提交時,如果線程池中有多余的線程則會使用空閑線程處理任務,如果沒有,則會把這個新任務添加到一個任務隊列椎間盤買個,一旦線程空閑時,則按照FIFO方法處理任務隊列中的任務數。
2)newCachedThreadPool()作用
返回一個可以根據實際情況調整線程池中線程數量的線程池。既該線程池中的線程數量不確定,是根據實際情況調整的。
如果該線程池中的所有線程都在工作,則此時有新的任務提交,則將會創建新的線程去提交,而假設之前有一些線程完成了任務,現在又有了新任務提交,則將不會創建新的線程,而是復用空閑的線程去處理任務,但是同時會設置空閑時間,如果該線程超過了空閑時間,則會被回收。
3)newSingleThreadExecutor()
該方法返回一個只有一個線程的線程池,既每次只能執行一個線程任務,多余的任務會保存到一個任務隊列中,等待這一個線程空閑,當這個線程空閑后按照FIFO的方式執行任務隊列中的任務。
4)newScheduledThreadPool
返回一個可以控制線程池內線程定時或者周期性執行某任務的線程池
5)newSingleThreadScheduledExecutor
返回一個可以控制線程池內線程定時或周期行執行某任務的線程池。只不過和上面的區別是該線程池的大小為1,而上面的可以指定線程池的大小。