溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

怎么使用java線程池

發布時間:2021-09-03 13:26:44 來源:億速云 閱讀:228 作者:小新 欄目:開發技術

這篇文章主要介紹了怎么使用java線程池,具有一定借鑒價值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。

1、線程是不是越多越好?

在學習多線程之前,讀者可能會有疑問?如果單線程跑得太慢,那么是否就能多創建多個線程來跑任務?并發的情況,線程是不是創建越多越好?這是一個很經典的問題,畫圖表示一下創建很多線程的情況,然后進行情況分析。

怎么使用java線程池

  • 創建線程和銷毀線程都是需要時間的,如果創建時間+銷毀時間>執行任務時間就很不劃算

  • 創建后的線程是需要內存去存放的,創建的線程對應一個Thread對象,對象是會占用JVM的堆內存的,根據jvm規范,一個線程默認最大棧大小為1M,這個??臻g也是需要從系統內存中分配的,所以線程越多,需要的內存就越多

  • 創建線程,操作系統是需要頻繁進行線程上下文切換的,所以線程創建太多,是會影響性能的

上下文切換(context switch):對于單核CPU來說,在一個時刻只能運行一個線程,對于并行來說,單核cpu也是可以支持多線程執行代碼的,CPU是通過給線程分配時間片來解決的,所謂時間片是CPU給每個線程分配的時間,時間片的時間是非常短的,所以執行完成一個時間片后,進行任務切換,切換之前先保存這個任務的狀態,以便于下次換回來的時候,可以加載這個任務的狀態,所以從保存任務狀態到再加載任務的過程稱為上下文切換,不僅在線程間可以上下文切換,進程也同樣可以

2、如何正確使用多線程?

  • 如果是計算型任務?

CPU數量的1~2倍即

  • 可如果是IO密集型任務?

就需要多一些線程,要根據具體的io阻塞時長來進行考量決定

3、Java線程池的工作原理

怎么使用java線程池

  • 接收任務,放入線程池的任務倉庫

  • 工作線程從線程池的任務倉庫取,執行

  • 沒有任務時,線程阻塞,有任務時喚醒線程

4、掌握JUC線程池API

  • Executor : 接口類

  • ExecutorService:加入關閉方法和對Runnable、Callable、Future的支持

怎么使用java線程池

  • shutdown:已經提交的會執行完成

  • shutdownNow:正在執行的會執行完成,未來執行的返回

  • awaitTermination:阻塞等待任務關閉完成

  • submit類型的:都是提交任務的,支持Runnable和Callable

  • invokeAll類型的:執行集合中所有任務

ScheduleExecutorService :加入對定時任務的支持

怎么使用java線程池

其中schedule(Runablle , long, Timeunit)schedule(Callable<V> , long, TimeUnit)表示的是多久后執行,而scheduleAtFixedRate方法和scheduleWithFixedDelay方法表示的都是周期性重復執行的

再描述scheduleAtFixedRate方法和scheduleWithFixedDelay方法的區別:

scheduleAtFixedRate:以固定的時間頻率重復執行任務,如每10s ,也就是兩個任務直接以固定的時間間隔執行,不管任務執行完成與否

怎么使用java線程池

scheduleWithFixedDelay:以固定的任務時延遲來重復執行任務,這種任務不管任務執行多久都執行完成,然后隔預定的如3s,接著執行下一個任務,每個任務之間的間隔都是一樣的

怎么使用java線程池

Executors:快速得到線程池的工具類,創建線程池的工廠類

  • newFixedThreadPool(int nThreads):創建一個固定大小、任務隊列 無界的線程池。線程池的核心線程數=最大線程池=nThreads

  • newCachedThreadPool():創建的是一個大小無界的緩沖線程池。它的任務隊列是一個同步隊列。如果隊列中有空閑的線程,則用空閑線程執行,如果沒有就創建新線程執行。池中線程空閑超過60s,就會被釋放。緩沖線程池使用于執行耗時比較小的異步任務。線程池的核心線程數=0,最大線程池=Integer.MAX_VALUE

  • newSingleThreadExecutor():創建的是只有一個線程來執行無界任務隊列的單一線程池。該線程池按順序執行一個一個加入的任務,任何時刻都只有一個線程在執行。單一線程池和newFixedThreadPool(1)的區別在于,單一線程池的池大小是不能再改變的

  • newScheduleThreadPool(int corePoolSize): 能定時執行任務的線程池,該池的核心線程數由參數corePoolSize指定,最大線程數=Integer.MAX_VALUE

  • newWorkStealingPool():以當前系統可用的處理器數作為并行級別創建的work-stealing thread pool(ForkJoinPool)

  • newWorkStealingPool(int parallelism):以指定的parallelism并行級別創建的work-stealing thread pool(ForkJoinPool)

ThreadPoolExecutor:線程池的標準實現

怎么使用java線程池

下面列舉出ThreadPoolExecutor的主要參數:

參數描述
corePoolSize核心線程數量
maxPoolSize最大線程數量
keepAliveTime+時間單位空閑線程的存活時間
ThreadFactory線程工廠,用于創建線程
workQueue用于存放任務的隊列,可以稱之為工作隊列
Handler用于處理被拒絕的任務

雖然Executors使用起來很方便,不過在阿里編程規范里是強調了慎用Executors創建線程池,下面摘錄自阿里編程規范手冊:

【強制】線程池不允許使用Executors去創建,而是通過ThreadPoolExecutor的方式,
這樣的處理方式讓寫的同學更加明確線程池的運行規則,規避資源耗盡的風險。
說明:Executors各個方法的弊端:
1)newFixedThreadPool和newSingleThreadExecutor:
??主要問題是堆積的請求處理隊列可能會耗費非常大的內存,甚至OOM。
2)newCachedThreadPool和newScheduledThreadPool:
??主要問題是線程數最大數是Integer.MAX_VALUE,可能會創建數量非常多的線程,甚至OOM。

ThreadPoolExecutor的基本參數:

new ThreadPoolExecutor(
				2, // 核心線程數 
				5, // 最大線程數
                60L, // keepAliveTime,線程空閑超過這個數,就會被銷毀釋放
                TimeUnit.SECONDS, // keepAliveTime的時間單位
                new ArrayBlockingQueue(5)); // 傳入邊界為5的工作隊列

畫流程圖表示,線程池的核心參數是corePoolSize、maxPoolSize、workQueue(工作隊列)

怎么使用java線程池

線程池工作原理示意圖:任務可以一直放,直到線程池滿了的情況,才會拒絕,然后除了核心線程,其它的線程會被合理回收。所以正常情況下,線程池中的線程數量會處在 corePoolSize 與 maximumPoolSize 的閉區間內

怎么使用java線程池

ThreadPoolExecutor基本實例:

ExecutorService service = new ThreadPoolExecutor(2, 5,
                60L, TimeUnit.SECONDS,
                new ArrayBlockingQueue(5));
 service.execute(() ->{
     System.out.println(String.format("thread name:%s",Thread.currentThread().getName()));
 });
  // 避免內存泄露,記得關閉線程池
 service.shutdown();

ThreadPoolExecutor加上Callable、Future使用的例子:

public static void  main(String[] args) {
	ExecutorService service = new ThreadPoolExecutor(2, 5,
	                60L, TimeUnit.SECONDS,
	                new ArrayBlockingQueue(5));	
	Future<Integer> future = service.submit(new CallableTask());
	Thread.sleep(3000);
	System.out.println("future is done?" + future.isDone());
	if (future.isDone()) {
	    System.out.println("callableTask返回參數:"+future.get());
	}
	service.shutdown();
}
static class CallableTask implements Callable<Integer>{
     @Override
     public Integer call() {
         return ThreadLocalRandom.current().ints(0, (99 + 1)).limit(1).findFirst().getAsInt();
     }
 }

感謝你能夠認真閱讀完這篇文章,希望小編分享的“怎么使用java線程池”這篇文章對大家有幫助,同時也希望大家多多支持億速云,關注億速云行業資訊頻道,更多相關知識等著你來學習!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女