欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

一篇文章帶你深入了解Java線程池

 更新時間:2021年08月02日 11:50:10   作者:Java盤魚宴  
這篇文章主要介紹了Java 線程池的相關(guān)資料,文中講解非常細(xì)致,幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下,希望能給你帶來幫助

線程池模型

一般的池化模型會有兩個方法,用于獲取資源和釋放資源,就像這樣:

public interface XXPool{
    XX acquire(); 
    void release();
}

但是,工程中的線程池一般是生產(chǎn)者和消費者模型,線程池是消費者,任務(wù)的提交者是生產(chǎn)者,下面是一個簡化的線程池模型:

//簡化的線程池,僅用來說明工作原理
class MyThreadPool{
  //利用阻塞隊列實現(xiàn)生產(chǎn)者-消費者模式
  BlockingQueue<Runnable> workQueue;
  //保存內(nèi)部工作線程
  List<WorkerThread> threads 
    = new ArrayList<>();
  // 構(gòu)造方法
  MyThreadPool(int poolSize, 
    BlockingQueue<Runnable> workQueue){
    this.workQueue = workQueue;
    // 創(chuàng)建工作線程
    for(int idx=0; idx<poolSize; idx++){
      WorkerThread work = new WorkerThread();
      work.start();
      threads.add(work);
    }
  }
  // 提交任務(wù)
  void execute(Runnable command){
    workQueue.put(command);
  }
  // 工作線程負(fù)責(zé)消費任務(wù),并執(zhí)行任務(wù)
  class WorkerThread extends Thread{
    public void run() {
      //循環(huán)取任務(wù)并執(zhí)行
      while(true){ ①
        Runnable task = workQueue.take();
        task.run();
      } 
    }
  }  
}

/** 下面是使用示例 **/
// 創(chuàng)建有界阻塞隊列
BlockingQueue<Runnable> workQueue = 
  new LinkedBlockingQueue<>(2);
// 創(chuàng)建線程池  
MyThreadPool pool = new MyThreadPool(
  10, workQueue);
// 提交任務(wù)  
pool.execute(()->{
    System.out.println("hello");
});

常用線程池

ThreadPoolExecutor

在工程中,我們會使用Executors來快速new一個線程池,例如:

ExecutorService executorService = Executors.newFixedThreadPool(threadPoolNum, r -> new Thread(r, threadName));

Executors底層使用的是 ThreadPoolExecutor,我們可以通過ThreadPoolExecutor構(gòu)造函數(shù)來了解ThreadPoolExecutor的一些行為。

ThreadPoolExecutor(
  int corePoolSize,
  int maximumPoolSize,
  long keepAliveTime,
  TimeUnit unit,
  BlockingQueue<Runnable> workQueue,
  ThreadFactory threadFactory,
  RejectedExecutionHandler handler)

構(gòu)造函數(shù)參數(shù)說明

corePoolSize:表示線程池保有的最小線程數(shù)。

maximumPoolSize:表示線程池創(chuàng)建的最大線程數(shù)。

keepAliveTime & unit:如果一個線程空閑了keepAliveTime & unit這么久,而且線程池的線程數(shù)大于 corePoolSize ,那么這個空閑的線程就要被回收了。

workQueue:工作隊列,和上面示例代碼的工作隊列同義。

threadFactory:通過這個參數(shù)你可以自定義如何創(chuàng)建線程,例如你可以給線程指定一個有意義的名字。

handler:通過這個參數(shù)你可以自定義任務(wù)的拒絕策略。如果線程池中所有的線程都在忙碌,并且工作隊列也滿了(前提是工作隊列是有界隊列),那么此時提交任務(wù),線程池就會拒絕接收。至于拒絕的策略,你可以通過 handler 這個參數(shù)來指定。

ThreadPoolExecutor 已經(jīng)提供了以下 4 種策略。

  • CallerRunsPolicy:提交任務(wù)的線程自己去執(zhí)行該任務(wù)。
  • AbortPolicy:默認(rèn)的拒絕策略,會 throws RejectedExecutionException。
  • DiscardPolicy:直接丟棄任務(wù),沒有任何異常拋出。
  • DiscardOldestPolicy:丟棄最老的任務(wù),其實就是把最早進(jìn)入工作隊列的任務(wù)丟棄,然后把新任務(wù)加入到工作隊列。

 線程池默認(rèn)工作行為

不會初始化 corePoolSize 個線程,有任務(wù)來了才創(chuàng)建工作線程;

當(dāng)核心線程滿了之后不會立即擴容線程池,而是把任務(wù)堆積到工作隊列中;

當(dāng)工作隊列滿了后擴容線程池,一直到線程個數(shù)達(dá)到 maximumPoolSize 為止;(如果線程池還沒有擴容到最大線程數(shù)但是工作隊列已經(jīng)溢出,溢出的請求會被拒絕)

如果隊列已滿且達(dá)到了最大線程后還有任務(wù)進(jìn)來,按照拒絕策略處理;

當(dāng)線程數(shù)大于核心線程數(shù)時,線程等待 keepAliveTime 后還是沒有任務(wù)需要處理的話,收縮線程到核心線程數(shù)。

ForkJoinPool

Fork/Join 是一個并行計算的框架,主要就是用來支持分治任務(wù)模型的,這個計算框架里的 Fork 對應(yīng)的是分治任務(wù)模型里的任務(wù)分解,Join 對應(yīng)的是結(jié)果合并。

Fork/Join 計算框架主要包含兩部分,一部分是分治任務(wù)的線程池 ForkJoinPool,另一部分是分治任務(wù) ForkJoinTask。這兩部分的關(guān)系類似于 ThreadPoolExecutor 和 Runnable 的關(guān)系,都可以理解為提交任務(wù)到線程池,只不過分治任務(wù)有自己獨特類型 ForkJoinTask。

ForkJoinPool 主要適用于計算密集型任務(wù),Java中的parallelStream底層使用的就是ForkJoinPool。

下面是使用ForkJoinPool的一個簡單例子:

  public static void main(String[] args) {
        ForkJoinPool forkJoinPool = new ForkJoinPool(4);

        Fibonacci fibonacci = new Fibonacci(5);
        Integer res = forkJoinPool.invoke(fibonacci);

        System.out.println(res);
    }

    static class Fibonacci extends RecursiveTask<Integer>{
        final int n;
        Fibonacci(int n){
            this.n = n;
        }
        @Override
        protected Integer compute() {
            if(n<=1){
                return n;
            }
            Fibonacci f1 = new Fibonacci(n-1);
            f1.fork();
            Fibonacci f2 = new Fibonacci(n-2);
            return f2.compute() + f1.join();
        }
    }

FutureTask

我們可以通過FutureTask(Future接口的實現(xiàn)類)獲取線程執(zhí)行結(jié)果。FutureTask主要方法如下:

// 取消任務(wù)
boolean cancel(
  boolean mayInterruptIfRunning);
// 判斷任務(wù)是否已取消  
boolean isCancelled();
// 判斷任務(wù)是否已結(jié)束
boolean isDone();
// 獲得任務(wù)執(zhí)行結(jié)果
get();
// 獲得任務(wù)執(zhí)行結(jié)果,支持超時
get(long timeout, TimeUnit unit);

其中,兩個 get() 方法都是阻塞式的,如果被調(diào)用的時候,任務(wù)還沒有執(zhí)行完,那么調(diào)用 get() 方法的線程會阻塞,直到任務(wù)執(zhí)行完才會被喚醒。

ExecutorService executorService = Executors.newFixedThreadPool(10);
        Future<Integer> future = executorService.submit(() -> {
            return 1 + 1;
        });
        Integer res = future.get();
        System.out.println(res);
        Integer res2 = future.get(1000, TimeUnit.SECONDS);
        System.out.println(res2);

FutureTask 實現(xiàn)了 Runnable 和 Future 接口,由于實現(xiàn)了 Runnable 接口,所以可以將 FutureTask 對象作為任務(wù)提交給 ThreadPoolExecutor 去執(zhí)行。

// 創(chuàng)建FutureTask
FutureTask<Integer> futureTask
  = new FutureTask<>(()-> 1+2);
// 創(chuàng)建線程池
ExecutorService es = 
  Executors.newCachedThreadPool();
// 提交FutureTask 
es.submit(futureTask);
// 獲取計算結(jié)果
Integer result = futureTask.get();

線程數(shù)量分析

多線程可以提高程序的響應(yīng)速度和吞吐量,創(chuàng)建線程的數(shù)量會對實際效果產(chǎn)生非常大的影響,線程太少會浪費CPU的資源,線程太多則會導(dǎo)致線程的頻繁切換,系統(tǒng)性能反而會下降。

根據(jù)程序類型的不同,我們可以將我們的程序分為IO密集型和CPU密集型兩種,這兩種程序計算最佳線程數(shù)的方法有所不同。

CPU密集型

對于 CPU 密集型計算,多線程本質(zhì)上是提升多核 CPU 的利用率,所以對于一個 4 核的 CPU,每個核一個線程,理論上創(chuàng)建 4 個線程就可以了,再多創(chuàng)建線程也只是增加線程切換的成本。所以,對于 CPU 密集型的計算場景,理論上“線程的數(shù)量 =CPU 核數(shù)”就是最合適的。不過在工程上,線程的數(shù)量一般會設(shè)置為“CPU 核數(shù) +1”,這樣的話,當(dāng)線程因為偶爾的內(nèi)存頁失效或其他原因?qū)е伦枞麜r,這個額外的線程可以頂上,從而保證 CPU 的利用率。

IO密集型

對于I/O 密集型計算場景,由于計算資源與IO資源是各自獨立的資源,在CPU執(zhí)行其他線程的任務(wù)時,IO仍能繼續(xù),因此對于IO密集型的程序,最佳線程數(shù)與程序中 CPU 計算和 I/O 操作的耗時比相關(guān)。

根據(jù)上訴分析,我們可以得出最佳線程數(shù)的計算公式:

最佳線程數(shù) = 1 +(I/O 耗時 / CPU 耗時)

對于多核CPU,只需進(jìn)行同比擴大就行:

最佳線程數(shù) =CPU 核數(shù) * [ 1 +(I/O 耗時 / CPU 耗時)]

對于最佳線程數(shù)是多少,以上只是理論分析,由于實際生產(chǎn)環(huán)境中,一臺機器可能會跑多個服務(wù),一個服務(wù)可能會有多個線程池,因此最佳線程數(shù)還是要根據(jù)實際生產(chǎn)情況進(jìn)行調(diào)整,理論值僅供參考。

總結(jié)

本篇文章就到這里了,希望能給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!

相關(guān)文章

  • Springboot配置管理Externalized?Configuration深入探究

    Springboot配置管理Externalized?Configuration深入探究

    這篇文章主要介紹了Springboot配置管Externalized?Configuration深入探究,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2024-01-01
  • Java數(shù)據(jù)結(jié)構(gòu)之鏈表相關(guān)知識總結(jié)

    Java數(shù)據(jù)結(jié)構(gòu)之鏈表相關(guān)知識總結(jié)

    今天給大家?guī)黻P(guān)于Java數(shù)據(jù)結(jié)構(gòu)的相關(guān)知識,文章圍繞Java鏈表展開,文中有非常詳細(xì)的介紹及代碼示例,需要的朋友可以參考下
    2021-06-06
  • Java如何確定兩個區(qū)間范圍是否有交集

    Java如何確定兩個區(qū)間范圍是否有交集

    這篇文章主要介紹了Java如何確定兩個區(qū)間范圍是否有交集問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-12-12
  • Java設(shè)計模式之模板方法模式

    Java設(shè)計模式之模板方法模式

    這篇文章介紹了Java設(shè)計模式之模板方法模式,文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-10-10
  • 基于SpringMVC實現(xiàn)網(wǎng)頁登錄攔截

    基于SpringMVC實現(xiàn)網(wǎng)頁登錄攔截

    SpringMVC的處理器攔截器類似于Servlet開發(fā)中的過濾器Filter,用于對處理器進(jìn)行預(yù)處理和后處理。因此,本文將為大家介紹如何通過SpringMVC實現(xiàn)網(wǎng)頁登錄攔截功能,需要的小伙伴可以了解一下
    2021-12-12
  • Java中MyBatis Plus知識點總結(jié)

    Java中MyBatis Plus知識點總結(jié)

    在本篇文章里小編給大家整理一篇關(guān)于Java中MyBatis Plus知識點總結(jié),需要的朋友們參考下。
    2019-10-10
  • SpringBoot中使用@Async注解失效場景及說明

    SpringBoot中使用@Async注解失效場景及說明

    在Spring?Boot中,@Async注解就像一把刀,能幫你輕松處理那些耗時的任務(wù),讓主線程可以繼續(xù)忙別的事兒,不過,跟所有強大的工具一樣,用不好它也可能出岔子,為了避免這些坑,咱們得深入了解下@Async注解,接下來,咱們就來聊聊7種常見的@Async失效情況,需要的朋友可以參考下
    2024-07-07
  • 如何在 Spring Boot 中配置和使用 CSRF 保護(hù)

    如何在 Spring Boot 中配置和使用 CSRF 保護(hù)

    CSRF是一種網(wǎng)絡(luò)攻擊,它利用已認(rèn)證用戶的身份來執(zhí)行未經(jīng)用戶同意的操作,Spring Boot 提供了內(nèi)置的 CSRF 保護(hù)機制,可以幫助您防止這種類型的攻擊,這篇文章主要介紹了Spring?Boot?中的?CSRF?保護(hù)配置的使用方法,需要的朋友可以參考下
    2023-09-09
  • Java Thread之Sleep()使用方法及總結(jié)

    Java Thread之Sleep()使用方法及總結(jié)

    這篇文章主要介紹了Java Thread之Sleep()使用方法及總結(jié),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • Java中關(guān)鍵字final finally finalize的區(qū)別介紹

    Java中關(guān)鍵字final finally finalize的區(qū)別介紹

    這篇文章主要給大家分享的是 Java中final,finally,finalize 到底有什么區(qū)別,文章圍繞final,finally,finalize的相關(guān)資料展開詳細(xì)內(nèi)容,具有一定的參考的價值,需要的朋友可以參考一下
    2022-04-04

最新評論