1. 程式人生 > >Java中的執行緒池種類

Java中的執行緒池種類

1. newSingleThreadExecutor

建立方式:

ExecutorService pool = Executors.newSingleThreadExecutor();

一個單執行緒的執行緒池。這個執行緒池只有一個執行緒在工作,也就是相當於單執行緒序列執行所有任務。如果這個唯一的執行緒因為異常結束,那麼會有一個新的執行緒來替代它。此執行緒池保證所有任務的執行順序按照任務的提交順序執行。

使用方式:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPool
{

   public static void main(String[] args) {
       ExecutorService pool = Executors.newSingleThreadExecutor();
       for (int i = 0; i < 10; i++) {
           pool.execute(() -> {
               System.out.println(Thread.currentThread().getName() + "\t開始發車啦....");
           });
       }
   }
}

輸出結果如下:

pool-1-thread-1    開始發車啦....
pool-1-thread-1    開始發車啦....
pool-1-thread-1    開始發車啦....
pool-1-thread-1    開始發車啦....
pool-1-thread-1    開始發車啦....
pool-1-thread-1    開始發車啦....
pool-1-thread-1    開始發車啦....
pool-1-thread-1    開始發車啦....
pool-1-thread-1    開始發車啦....
pool-1-thread-1    開始發車啦....

從輸出的結果我們可以看出,一直只有一個執行緒在執行。

2.newFixedThreadPool

建立方式:

ExecutorService pool = Executors.newFixedThreadPool(10);

建立固定大小的執行緒池。每次提交一個任務就建立一個執行緒,直到執行緒達到執行緒池的最大大小。執行緒池的大小一旦達到最大值就會保持不變,如果某個執行緒因為執行異常而結束,那麼執行緒池會補充一個新執行緒。

使用方式:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPool {
   public static void main(String[] args) {
       ExecutorService pool = Executors.newFixedThreadPool(10);
       for (int i = 0; i < 10; i++) {
           pool.execute(() -> {
               System.out.println(Thread.currentThread().getName() + "\t開始發車啦....");
           });
       }
   }
}

輸出結果如下:

pool-1-thread-1    開始發車啦....
pool-1-thread-4    開始發車啦....
pool-1-thread-3    開始發車啦....
pool-1-thread-2    開始發車啦....
pool-1-thread-6    開始發車啦....
pool-1-thread-7    開始發車啦....
pool-1-thread-5    開始發車啦....
pool-1-thread-8    開始發車啦....
pool-1-thread-9    開始發車啦....
pool-1-thread-10 開始發車啦....

3. newCachedThreadPool

建立方式:

ExecutorService pool = Executors.newCachedThreadPool();

建立一個可快取的執行緒池。如果執行緒池的大小超過了處理任務所需要的執行緒,那麼就會回收部分空閒的執行緒,當任務數增加時,此執行緒池又新增新執行緒來處理任務。

使用方式如上2所示。

4.newScheduledThreadPool

建立方式:

ScheduledExecutorService pool = Executors.newScheduledThreadPool(10);

此執行緒池支援定時以及週期性執行任務的需求。

使用方式:

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ThreadPool {
   public static void main(String[] args) {
       ScheduledExecutorService pool = Executors.newScheduledThreadPool(10);
       for (int i = 0; i < 10; i++) {
           pool.schedule(() -> {
               System.out.println(Thread.currentThread().getName() + "\t開始發車啦....");
           }, 10, TimeUnit.SECONDS);
       }
   }
}

上面演示的是延遲10秒執行任務,如果想要執行週期性的任務可以用下面的方式,每秒執行一次

//pool.scheduleWithFixedDelay也可以
pool.scheduleAtFixedRate(() -> {
               System.out.println(Thread.currentThread().getName() + "\t開始發車啦....");
}, 1, 1, TimeUnit.SECONDS);

5.newWorkStealingPool

newWorkStealingPool是jdk1.8才有的,會根據所需的並行層次來動態建立和關閉執行緒,通過使用多個佇列減少競爭,底層用的ForkJoinPool來實現的。ForkJoinPool的優勢在於,可以充分利用多cpu,多核cpu的優勢,把一個任務拆分成多個“小任務”,把多個“小任務”放到多個處理器核心上並行執行;當多個“小任務”執行完成之後,再將這些執行結果合併起來即可。

說說執行緒池的拒絕策略

當請求任務不斷的過來,而系統此時又處理不過來的時候,我們需要採取的策略是拒絕服務。RejectedExecutionHandler介面提供了拒絕任務處理的自定義方法的機會。在ThreadPoolExecutor中已經包含四種處理策略。

  • AbortPolicy策略:該策略會直接丟擲異常,阻止系統正常工作。

public static class AbortPolicy implements RejectedExecutionHandler {
   public AbortPolicy() { }
   public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
       throw new RejectedExecutionException("Task " + r.toString() +
                                                " rejected from " +
                                                e.toString());
   }
}
  • CallerRunsPolicy 策略:只要執行緒池未關閉,該策略直接在呼叫者執行緒中,運行當前的被丟棄的任務。

public static class CallerRunsPolicy implements RejectedExecutionHandler {
   public CallerRunsPolicy() { }
   public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
       if (!e.isShutdown()) {
               r.run();
       }
   }
}
  • DiscardOleddestPolicy策略: 該策略將丟棄最老的一個請求,也就是即將被執行的任務,並嘗試再次提交當前任務。

public static class DiscardOldestPolicy implements RejectedExecutionHandler {
   public DiscardOldestPolicy() { }
   public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
       if (!e.isShutdown()) {
           e.getQueue().poll();
           e.execute(r);
       }
   }
}
  • DiscardPolicy策略:該策略默默的丟棄無法處理的任務,不予任何處理。

public static class DiscardPolicy implements RejectedExecutionHandler {
   public DiscardPolicy() { }
   public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
   }
}

除了JDK預設為什麼提供的四種拒絕策略,我們可以根據自己的業務需求去自定義拒絕策略,自定義的方式很簡單,直接實現RejectedExecutionHandler介面即可

比如Spring integration中就有一個自定義的拒絕策略CallerBlocksPolicy,將任務插入到佇列中,直到佇列中有空閒並插入成功的時候,否則將根據最大等待時間一直阻塞,直到超時。

package org.springframework.integration.util;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class CallerBlocksPolicy implements RejectedExecutionHandler {
   private static final Log logger = LogFactory.getLog(CallerBlocksPolicy.class);
   private final long maxWait;
   /**
    * @param maxWait The maximum time to wait for a queue slot to be
    * available, in milliseconds.
    */

   public CallerBlocksPolicy(long maxWait) {
       this.maxWait = maxWait;
   }
   @Override
   public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
       if (!executor.isShutdown()) {
           try {
               BlockingQueue<Runnable> queue = executor.getQueue();
               if (logger.isDebugEnabled()) {
                   logger.debug("Attempting to queue task execution for " + this.maxWait + " milliseconds");
               }
               if (!queue.offer(r, this.maxWait, TimeUnit.MILLISECONDS)) {
                   throw new RejectedExecutionException("Max wait time expired to queue task");
               }
               if (logger.isDebugEnabled()) {
                   logger.debug("Task execution queued");
               }
           }
           catch (InterruptedException e) {
               Thread.currentThread().interrupt();
               throw new RejectedExecutionException("Interrupted", e);
           }
       }
       else {
           throw new RejectedExecutionException("Executor has been shut down");
       }
   }
}

定義好之後如何使用呢?光定義沒用的呀,一定要用到執行緒池中呀,可以通過下面的方式自定義執行緒池,指定拒絕策略。

BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(100);
ThreadPoolExecutor executor = new ThreadPoolExecutor(
   10, 100, 10, TimeUnit.SECONDS, workQueue, new CallerBlocksPolicy());

execute和submit的區別?

在前面的講解中,我們執行任務是用的execute方法,除了execute方法,還有一個submit方法也可以執行我們提交的任務。

這兩個方法有什麼區別呢?分別適用於在什麼場景下呢?我們來做一個簡單的分析。

execute適用於不需要關注返回值的場景,只需要將執行緒丟到執行緒池中去執行就可以了

public class ThreadPool {
   public static void main(String[] args) {
       ExecutorService pool = Executors.newFixedThreadPool(10);
       pool.execute(() -> {
           System.out.println(Thread.currentThread().getName() + "\t開始發車啦....");
       });
   }
}

submit方法適用於需要關注返回值的場景,submit方法的定義如下:

public interface ExecutorService extends Executor {
  ...
  <T> Future<T> submit(Callable<T> task);
  <T> Future<T> submit(Runnable task, T result);
  Future<?> submit(Runnable task);
  ...
}

其子類AbstractExecutorService實現了submit方法,可以看到無論引數是Callable還是Runnable,最終都會被封裝成RunnableFuture,然後再呼叫execute執行。

    /**
    * @throws RejectedExecutionException {@inheritDoc}
    * @throws NullPointerException       {@inheritDoc}
    */

   public Future<?> submit(Runnable task) {
       if (task ==

相關推薦

沉澱再出發:java執行解析

沉澱再出發:java中執行緒池解析 一、前言    在多執行緒執行的環境之中,如果執行緒執行的時間短但是啟動的執行緒又非常多,執行緒運轉的時間基本上浪費在了建立和銷燬上面,因此有沒有一種方式能夠讓一個執行緒執行完自己的任務之後又被重複使用呢?執行緒池的出現就是為了解決這個問題。到了現在

Java執行基本api及其作用

1.執行緒池相關的類 2.重要類的api及其方法 Executors.newCachedThreadPool() 建立一個可快取的執行緒池 Executors.newSingleThreadExecutor();建立一個只有一個執行緒執行的 不可修改的執行緒池  

java執行的生命週期

執行緒池生命週期包括: RUNNING:接收新的任務並處理佇列中的任務 SHUTDOWN:不接收新的任務,但是處理佇列中的任務 STOP:不接收新的任務,不處理佇列中的任務,同時中斷處理中的任務 TIDYING:所有的任務處理完成,有效的執行緒數是0 TERMINATED:termin

Java執行,你真的會用嗎

轉載自   Java中執行緒池,你真的會用嗎 在《深入原始碼分析Java執行緒池的實現原理》這篇文章中,我們介紹過了Java中執行緒池的常見用法以及基本原理。 在文中有這樣一段描述: 可以通過Executors靜態工廠構建執行緒池,但一般不建議這樣使用。 關於這個

java執行的生命週期與執行中斷

執行緒池生命週期包括: RUNNING:接收新的任務並處理佇列中的任務 SHUTDOWN:不接收新的任務,但是處理佇列中的任務 STOP:不接收新的任務,不處理佇列中的任務,同時中斷處理中的任務 TIDYING:所有的任務處理完成,有效的執行緒數是0 TE

Java執行,你真的瞭解會用嗎

在《 深入原始碼分析Java執行緒池的實現原理 》這篇文章中,我們介紹過了Java中執行緒池的常見用法以及基本原理。 在文中有這樣一段描述: 可以通過Executors靜態工廠構建執行緒池,但一般不建議這樣使用。 關於這個問題,在那篇文章中並沒有深入的展開。作者之所以這

Java執行,你真的會用嗎?

  我騎著小毛驢,喝著大紅牛哇,哩個啷格里格朗,別問我為什麼這木開心,如果活著不是為了浪蕩那將毫無意義      今天來捋一捋我們平日經常用的instanceof和typeof的一些小問題      typeof:      typeof裡面是由一個小坑的  我們今天著重來研

Java執行ThreadPoolExecutor原理探究

一、 前言 執行緒池主要解決兩個問題:一方面當執行大量非同步任務時候執行緒池能夠提供較好的效能,,這是因為使用執行緒池可以使每個任務的呼叫開銷減少(因為執行緒池執行緒是可以複用的)。另一方面執行緒池提供了一種資源限制和管理的手段,比如當執行一系列任務時候對執行緒的管理,每個ThreadPool

Java高併發程式設計(十一):Java執行

在開發過程中,合理地使用執行緒池能夠帶來3個好處。 降低資源消耗。通過重複利用已建立的執行緒降低執行緒建立和銷燬造成的消耗。 提高響應速度。當任務到達時,任務可以不需要等到執行緒建立就能立即執行。 提高執行緒的可管理性。執行緒是稀缺資源,如果無限制地建立

java執行的幾種實現方式

1、執行緒池簡介:     多執行緒技術主要解決處理器單元內多個執行緒執行的問題,它可以顯著減少處理器單元的閒置時間,增加處理器單元的吞吐能力。         假設一個伺服器完成一項任務所需時間為:T1 建立執行緒時間,T2 線上程中執行任務的時間,T3 銷燬執

java執行ExecutorService 執行管理

 程式碼: package com.bob.test; import java.util.concurrent.ExecutorService; import java.util.concurren

Java執行種類

1. newSingleThreadExecutor建立方式:ExecutorService pool = Executors.newSingleThreadExecutor();一個單執行緒的執行緒池。這個執行緒池只有一個執行緒在工作,也就是相當於單執行緒序列執行所有任務。

java執行執行的利弊(android適用)

介紹new Thread的弊端及Java四種執行緒池的使用,對Android同樣適用。本文是基礎篇,後面會分享下執行緒池一些高階功能。 1、new Thread的弊端 執行一個非同步任務你還只是如下new Thread嗎? new Thread(new Runnable(

Java執行ThreadPoolExecutor解析及Executors類提供的靜態方法來建立執行

上面的程式碼可能看起來不是那麼容易理解,下面我們一句一句解釋:   首先,判斷提交的任務command是否為null,若是null,則丟擲空指標異常;   接著是這句,這句要好好理解一下: if (poolSize >= corePoolSize || !addIfUnderCorePoolSize(c

java設定執行執行的名字

專案中使用ThreadPoolExecutor進行多執行緒開發。使用起來很方便,但是當用jstack檢視堆疊資訊或者Jprofiler除錯效能的時候,看到的執行緒都是pool-1-thread-1\2\3\4之類的。如果一個系統中用到了多個執行緒池,就無法區分哪個執行緒造

Java執行種類、區別和適用場景

newCachedThreadPool:底層:返回ThreadPoolExecutor例項,corePoolSize為0;maximumPoolSize為Integer.MAX_VALUE;keepAliveTime為60L;unit為TimeUnit.SECONDS;workQueue為Synchronou

java.util.concurrent包執行Executors的使用

執行緒池的概念與Executors類的使用 (1)建立固定大小的執行緒池–當有多個任務時,會先按照執行緒池中的資料執行任務,其他任務處於等待過程中,等執行完這批任務後再執行下批任務。 (2)建立快

Java併發包執行ThreadPoolExecutor原理探究

一、執行緒池簡介   執行緒池的使用主要是解決兩個問題:①當執行大量非同步任務的時候執行緒池能夠提供更好的效能,在不使用執行緒池時候,每當需要執行非同步任務的時候直接new一個執行緒來執行的話,執行緒的建立和銷燬都是需要開銷的。而執行緒池中的執行緒是可複用的,不需要每次執行非同步任務的時候重新建立和銷燬執行

Java執行原始碼深入理解

在前面的文章中,我們使用執行緒的時候就去建立一個執行緒,這樣實現起來非常簡便,但是就會有一個問題: 如果併發的執行緒數量很多,並且每個執行緒都是執行一個時間很短的任務就結束了,這樣頻繁建立執行緒就會大大降低系統的效率,因為頻繁建立執行緒和銷燬執行

Java執行ThreadPoolExecutor實現原理

引言 執行緒池:可以理解為緩衝區,由於頻繁的建立銷燬執行緒會帶來一定的成本,可以預先建立但不立即銷燬,以共享方式為別人提供服務,一來可以提供效率,再者可以控制執行緒無線擴張。合理利用執行緒池能夠帶來三個好處: 降低資源消耗。通過重複利用已建立的執行緒降低執行緒建立和銷燬造