最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java線程池使用與原理詳解

 更新時(shí)間:2017年10月09日 08:38:27   作者:_Yasin  
這篇文章主要為大家詳細(xì)介紹了Java線程池使用與原理的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

線程池是什么?

我們可以利用java很容易創(chuàng)建一個(gè)新線程,同時(shí)操作系統(tǒng)創(chuàng)建一個(gè)線程也是一筆不小的開銷。所以基于線程的復(fù)用,就提出了線程池的概念,我們使用線程池創(chuàng)建出若干個(gè)線程,執(zhí)行完一個(gè)任務(wù)后,該線程會(huì)存在一段時(shí)間(用戶可以設(shè)定空閑線程的存活時(shí)間,后面會(huì)介紹),等到新任務(wù)來(lái)的時(shí)候就直接復(fù)用這個(gè)空閑線程,這樣就省去了創(chuàng)建、銷毀線程損耗。當(dāng)然空閑線程也會(huì)是一種資源的浪費(fèi)(所有才有空閑線程存活時(shí)間的限制),但總比頻繁的創(chuàng)建銷毀線程好太多。
下面是我的測(cè)試代碼

  /*
   * @TODO 線程池測(cè)試
   */
  @Test
  public void threadPool(){

    /*java提供的統(tǒng)計(jì)線程運(yùn)行數(shù),一開始設(shè)置其值為50000,每一個(gè)線程任務(wù)執(zhí)行完
     * 調(diào)用CountDownLatch#coutDown()方法(其實(shí)就是自減1)
     * 當(dāng)所有的線程都執(zhí)行完其值就為0
    */
    CountDownLatch count = new CountDownLatch(50000);
    long start = System.currentTimeMillis();
    Executor pool = Executors.newFixedThreadPool(10);//開啟線程池最多會(huì)創(chuàng)建10個(gè)線程
    for(int i=0;i<50000;i++){
      pool.execute(new Runnable() {
        @Override
        public void run() {
          System.out.println("hello");
          count.countDown();
        }
      });
    }

    while(count.getCount()!=0){//堵塞等待5w個(gè)線程運(yùn)行完畢

    }
    long end = System.currentTimeMillis();
    System.out.println("50個(gè)線程都執(zhí)行完了,共用時(shí):"+(end-start)+"ms");
  }


  /**
   *@TODO 手動(dòng)創(chuàng)建線程測(cè)試 
   */
  @Test
  public void thread(){
    CountDownLatch count = new CountDownLatch(50000);
    long start = System.currentTimeMillis();
    for(int i=0;i<50000;i++){
      Thread thread = new Thread(new Runnable() {

        @Override
        public void run() {
          System.out.println("hello");
          count.countDown();
        }
      });
      thread.start();
    }

    while(count.getCount()!=0){//堵塞等待5w個(gè)線程運(yùn)行完畢

    }
    long end = System.currentTimeMillis();
    System.out.println("50000個(gè)線程都執(zhí)行完了,共用時(shí):"+(end-start)+"ms");


  }

使用線程池5w線程運(yùn)行完大約為400ms,不使用線程池運(yùn)行大約為4350ms左右,其效率可見一斑(讀者可以自行測(cè)試,不過由于電腦配置不一樣,跑出來(lái)的數(shù)據(jù)會(huì)有差別,但使用線程池絕對(duì)是比創(chuàng)建線程要快的)。

java如何使用線程池?

上面的測(cè)試代碼中已經(jīng)使用了線程池,下面正式介紹一下。

java所有的線程池最頂層是一個(gè)Executor接口,其只有一個(gè)execute方法,用于執(zhí)行所有的任務(wù),java又提供了ExecutorService接口繼承自Executor并且擴(kuò)充了一下方法,在往下就是AbstractExecutorService這個(gè)抽象類,其實(shí)現(xiàn)了ExecutorService,最后就是ThreadPoolExecutor其繼承自上面的抽象類,我們常使用的java線程池就是創(chuàng)建的這個(gè)類的實(shí)例。

而上面我們使用Executors是一個(gè)工具類,它就是一個(gè)語(yǔ)法糖,為我們把各種不同的業(yè)務(wù)的線程池參數(shù)進(jìn)行封裝,進(jìn)行new操作。

 public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                   0L, TimeUnit.MILLISECONDS,
                   new LinkedBlockingQueue<Runnable>());
  }

上面就是Executors.newFixedThreadPool(10)的源碼。

下面重點(diǎn)來(lái)了,說一說ThreadPoolExecutor構(gòu)造方法各參數(shù)的意思。

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

上面這個(gè)構(gòu)造方法是最全的。

下面我們根據(jù)源碼來(lái)解釋部分參數(shù)意思,這樣更有說服力。

下面是ThreadPoolExecutor#execute方法,就是我們上面接口調(diào)用的execute實(shí)際執(zhí)行者。

 public void execute(Runnable command) {
    if (command == null)
      throw new NullPointerException();

    int c = ctl.get();
    if (workerCountOf(c) < corePoolSize) {
      if (addWorker(command, true))
        return;
      c = ctl.get();
    }
    if (isRunning(c) && workQueue.offer(command)) {
      int recheck = ctl.get();
      if (! isRunning(recheck) && remove(command))
        reject(command);
      else if (workerCountOf(recheck) == 0)
        addWorker(null, false);
    }
    else if (!addWorker(command, false))
      reject(command);
  }

ctl是一個(gè)AtomicInteger實(shí)例,是一個(gè)提供了原子語(yǔ)句的CAS操作的類,它用來(lái)記錄線程池中當(dāng)前運(yùn)行的線程數(shù)量加上-2^29,workCountOf方法就取得其絕對(duì)值(可以去看源碼如何實(shí)現(xiàn)),當(dāng)其小于corePoolSize時(shí),會(huì)調(diào)用addWorker方法(是用來(lái)創(chuàng)建一個(gè)新Workder,Workder會(huì)創(chuàng)建一個(gè)Thread,所以就是創(chuàng)建線程的方法),addWorkd創(chuàng)建線程過程中會(huì)跟corePoolSize或者maxnumPoolSize的值比較(當(dāng)傳入true會(huì)根corePoolSize比較,false會(huì)根據(jù)maxnumPoolSize比較,大于等于其值會(huì)創(chuàng)建失?。?。可見如何當(dāng)前運(yùn)行中的線程數(shù)量小于corePoolSize就是創(chuàng)建并且也會(huì)創(chuàng)建成功(
只簡(jiǎn)單的討論線程池Running狀態(tài)下)。

如果當(dāng)運(yùn)行中線程數(shù)大于等于corePoolSize時(shí),進(jìn)入第二個(gè)if,isRunning是跟SHUTDOWN(其值=0)比較,之前說過c等于當(dāng)前運(yùn)行的線程數(shù)量加上-2^29,如果當(dāng)前當(dāng)前運(yùn)行的線程數(shù)據(jù)達(dá)到2^29時(shí)其值就=0,isRunning返回false,else中在執(zhí)行addWorkd也會(huì)返回false(addWorkd也對(duì)其進(jìn)行了檢驗(yàn)),所以這表示線程池最多能支持2^29個(gè)線程同時(shí)運(yùn)行(足夠用了)。

workQueue.offer(command)就是將runnable加入等待隊(duì)列,加入等待隊(duì)列后runWorker方法會(huì)從隊(duì)列中獲取任務(wù)執(zhí)行的。如果當(dāng)前隊(duì)列采用的是有界隊(duì)列(ArrayBlockingQueue)當(dāng)隊(duì)列滿了offer就會(huì)返回false,這是就進(jìn)入else if,看!這里傳入了false,說明這里要跟maxnumPoolSize比較了,如果這里運(yùn)行的線程數(shù)大于等于maxnumPoolSize,那么這個(gè)線程任務(wù)就要被線程池拒絕了,執(zhí)行reject(command),拒絕方法中使用了我們ThreadPoolExecutor構(gòu)造方法中的RejectedExecutionHandler(拒絕策略),后面再詳細(xì)解釋。

經(jīng)過上面的結(jié)合源碼的介紹,下面對(duì)們ThreadPoolExecutor的參數(shù)介紹就好理解了。

線程池中線程創(chuàng)建和拒絕策略

corePoolSize,maxnumPoolSize,BlockingQueue這三個(gè)要一塊說

當(dāng)線程池運(yùn)行的線程小于corePoolSize時(shí),來(lái)一個(gè)新線程任務(wù)總是會(huì)新建一個(gè)線程來(lái)執(zhí)行;當(dāng)大于corePoolSize就會(huì)把任務(wù)加入到等待隊(duì)列blockingQueue中,如果你傳入的BlockingQueue是一個(gè)無(wú)界隊(duì)列(LinkedBlockingQueue)這是隊(duì)列可以存放“無(wú)窮多”的任務(wù),所有總是會(huì)加入隊(duì)列成功,跟maxnumPoolSize就沒關(guān)系了,這也表示線程池中線程數(shù)最多為corePoolSize個(gè);但是如果你傳入的是有界隊(duì)列(ArrayBlockingQueue,SynchronousQueue),當(dāng)隊(duì)列滿時(shí),并且線程數(shù)小于maxmunPoolSize就是創(chuàng)建新的線程直至線程數(shù)大于maxnumPoolSize;如果當(dāng)線程數(shù)量大于maxnumPoolSize時(shí),在加入任務(wù)就會(huì)被線程池拒絕。

RejectedExecutionHandler拒絕策略java給實(shí)現(xiàn)了4個(gè)AbortPolicy,CallerRunsPolicy,DiscardOldestPolicy,DiscardPolicy用戶也可以自己實(shí)現(xiàn)該接口實(shí)現(xiàn)自己的拒絕策略;第一個(gè)就是直接拋出異常,我們可以進(jìn)行trycatch處理;第二個(gè)就是該新任務(wù)直接運(yùn)行;第三個(gè)是取消隊(duì)列中最老的;第四個(gè)是取消當(dāng)前任務(wù)。

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • SpringBoot多環(huán)境配置方式的新手教程

    SpringBoot多環(huán)境配置方式的新手教程

    我們平時(shí)做項(xiàng)目的時(shí)候,一般都會(huì)分幾套環(huán)境,每一套環(huán)境的配置都是不一樣的,所以這篇文章就來(lái)為大家詳細(xì)介紹一下SpringBoot多環(huán)境配置方式,希望對(duì)大家有所幫助
    2023-11-11
  • 簡(jiǎn)單聊聊Java中驗(yàn)證碼功能的實(shí)現(xiàn)

    簡(jiǎn)單聊聊Java中驗(yàn)證碼功能的實(shí)現(xiàn)

    相信大家都經(jīng)常接觸到驗(yàn)證碼的,畢竟平時(shí)上網(wǎng)也能遇到各種驗(yàn)證碼,需要我們輸入驗(yàn)證碼進(jìn)行驗(yàn)證我們是人類,本篇文章就從這幾個(gè)方面出發(fā)說說驗(yàn)證碼,廢話不多說,下面開始正文
    2023-06-06
  • java結(jié)合keytool如何實(shí)現(xiàn)非對(duì)稱簽名和驗(yàn)證詳解

    java結(jié)合keytool如何實(shí)現(xiàn)非對(duì)稱簽名和驗(yàn)證詳解

    這篇文章主要給大家介紹了關(guān)于java結(jié)合keytool如何實(shí)現(xiàn)非對(duì)稱簽名和驗(yàn)證的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2018-08-08
  • Java 實(shí)戰(zhàn)項(xiàng)目之精品養(yǎng)老院管理系統(tǒng)的實(shí)現(xiàn)流程

    Java 實(shí)戰(zhàn)項(xiàng)目之精品養(yǎng)老院管理系統(tǒng)的實(shí)現(xiàn)流程

    讀萬(wàn)卷書不如行萬(wàn)里路,只學(xué)書上的理論是遠(yuǎn)遠(yuǎn)不夠的,只有在實(shí)戰(zhàn)中才能獲得能力的提升,本篇文章手把手帶你用java+Springboot+Maven+mybatis+Vue+Mysql實(shí)現(xiàn)一個(gè)精品養(yǎng)老院管理系統(tǒng),大家可以在過程中查缺補(bǔ)漏,提升水平
    2021-11-11
  • IntelliJ IDEA中如何調(diào)試Java Stream操作

    IntelliJ IDEA中如何調(diào)試Java Stream操作

    這篇文章主要介紹了IntelliJ IDEA中如何優(yōu)雅的調(diào)試Java Stream操作,在強(qiáng)大的IDEA插件支持下,stream的調(diào)試其實(shí)也沒那么難了,下面就來(lái)學(xué)習(xí)一下在IDEA中如何調(diào)試stream操作吧
    2022-05-05
  • Java并發(fā)編程之ConcurrentLinkedQueue源碼詳解

    Java并發(fā)編程之ConcurrentLinkedQueue源碼詳解

    今天帶小伙伴們學(xué)習(xí)一下Java并發(fā)編程之Java ConcurrentLinkedQueue源碼,本篇文章詳細(xì)分析了ConcurrentLinkedQueue源碼,有代碼示例,對(duì)正在學(xué)習(xí)java的小伙伴們很有幫助喲,需要的朋友可以參考下
    2021-05-05
  • CentOS7和8中安裝Maven3.8.4的簡(jiǎn)單步驟

    CentOS7和8中安裝Maven3.8.4的簡(jiǎn)單步驟

    maven是屬于apache的一個(gè)工具,主要是對(duì)java進(jìn)行編譯打包,解決依賴關(guān)系,下面這篇文章主要給大家介紹了關(guān)于CentOS7和8中安裝Maven3.8.4的相關(guān)資料,需要的朋友可以參考下
    2022-04-04
  • 淺談標(biāo)簽和JLabel類構(gòu)造方法

    淺談標(biāo)簽和JLabel類構(gòu)造方法

    這篇文章主要介紹了標(biāo)簽和JLabel類構(gòu)造方法,具有一定參考價(jià)值,需要的朋友可以參考下。
    2017-09-09
  • 如何使用?Spring?Boot?搭建?WebSocket?服務(wù)器實(shí)現(xiàn)多客戶端連接

    如何使用?Spring?Boot?搭建?WebSocket?服務(wù)器實(shí)現(xiàn)多客戶端連接

    本文介紹如何使用SpringBoot快速搭建WebSocket服務(wù)器,實(shí)現(xiàn)多客戶端連接和消息廣播,WebSocket協(xié)議提供全雙工通信,SpringBoot通過@ServerEndpoint簡(jiǎn)化配置,支持實(shí)時(shí)消息推送,適用于聊天室或通知系統(tǒng)等應(yīng)用場(chǎng)景
    2024-11-11
  • Java中classpath的基本概念和配置方法詳析

    Java中classpath的基本概念和配置方法詳析

    這篇文章主要介紹了Java中的classpath概念,包括其基本概念、設(shè)置方法以及在Java應(yīng)用中的作用,在IDE中的配置也進(jìn)行了詳細(xì)說明,并提到了一些通用注意事項(xiàng),需要的朋友可以參考下
    2025-02-02

最新評(píng)論

双江| 景宁| 安庆市| 福海县| 廊坊市| 弥渡县| 新丰县| 佛坪县| 黑龙江省| 彭州市| 科技| 阳信县| 武陟县| 霍山县| 鄂托克前旗| 汽车| 岚皋县| 新干县| 和平县| 永川市| 逊克县| 泗水县| 前郭尔| 天等县| 资溪县| 岳阳市| 宁蒗| 巴彦县| 绵竹市| 靖边县| 河东区| 无极县| 呼和浩特市| 临海市| 青岛市| 朝阳区| 马鞍山市| 长汀县| 寿宁县| 五常市| 桦川县|