多執行緒(七)JDK原生執行緒池
阿新 • • 發佈:2018-12-17
如同資料庫連線一樣,執行緒的建立、切換和銷燬同樣會耗費大量的系統資源。為了複用建立好的執行緒,減少頻繁建立執行緒的次數,提高執行緒利用率可以引用執行緒池技術。使用執行緒池的優勢有如下幾點:
1、保持一定數量的執行緒,減少了執行緒頻繁建立和銷燬資源消耗。
2、使用執行緒的時候直接由執行緒池中取出執行緒,省去了建立執行緒的時間,側面提高了系統的響應時間。
3、需要使用執行緒的時候直接從執行緒池中取出,避免了人為的不合理建立執行緒,減少了潛在的風險。
Doug Lea在實現JUC中提供了原生的執行緒池,並提供了各種執行緒管理策略來適應於不同的使用場景。使用的時候可通過Executors獲取各種執行緒池例項。
這裡提供了六對12個方法來建立ExecutorService,其中每種型別的ExecutorService可以適用於不同的應用場景,對執行緒的管理策略也各不相同。下面就看一下各個方法的註釋:
/** * Creates a thread pool that creates new threads as needed, but will reuse previously constructed threads when they are available. * 建立一個執行緒池,需要的時候會建立新的執行緒,如果有可用的執行緒則會複用以前已經建立好的執行緒。 * These pools will typically improve the performance of programs that execute many short-lived asynchronous tasks. * 這些執行緒池通常情況下可以提升哪些短期非同步任務的效能 * Calls to {@code execute} will reuse previously constructed threads if available. * 如果以建立的執行緒狀態可用的話,呼叫execute可以複用他們 * If no existing thread is available, a new thread will be created and added to the pool. * 如果不存在可用狀態的執行緒,那麼將會建立一個新執行緒同時會把該執行緒新增到執行緒池中 * Threads that have not been used for sixty seconds are terminated and removed from the cache. *那些超過60s沒用的執行緒將會被銷燬同時從快取中移除 * Thus, a pool that remains idle for long enough will not consume any resources. *因此長時間空閒的執行緒池不會消耗任何資源 * Note that pools with similar properties but different details (for example, timeout parameters) may be created using {@link ThreadPoolExecutor} constructors. *可以使用ThreadPoolExecutor建立性質相似但實現細節不同的執行緒池 * @return the newly created thread pool */ public static ExecutorService newCachedThreadPool(); //可以使用自定義的ThreadFactory 類建立執行緒,其它和無參方法一致 public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory);
/** * Creates a thread pool that reuses a fixed number of threads operating off a shared unbounded queue. *建立一個可重用、固定數量執行緒的執行緒池 * At any point, at most {@code nThreads} threads will be active processing tasks. *任何時間最多隻有 nThreads 個執行緒被啟用來執行任務 * If additional tasks are submitted when all threads are active, they will wait in the queue until a thread is available. * 當無可用空閒執行緒的時候,如果有新任務被提交,這些新任務將會一直等待直至有可用執行緒來執行。 * If any thread terminates due to a failure during execution prior to shutdown, a new one will take its place if needed to execute subsequent tasks. *如果任何執行緒正常關閉之前在執行過程中因失敗而提前終止,那麼如果有未被執行的後續任務,則會建立新的執行緒來繼續執行。 * The threads in the pool will exist until it is explicitly {@link ExecutorService#shutdown shutdown}. * 執行緒池中的所有執行緒在明確掉用shutdown之後將會退出 * * @param nThreads the number of threads in the pool * @return the newly created thread pool * @throws IllegalArgumentException if {@code nThreads <= 0} */ public static ExecutorService newFixedThreadPool(int nThreads); //可自定義ThreadFactory public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory);
/** * Creates a thread pool that can schedule commands to run after a given delay, or to execute periodically. * 建立一個執行緒池,該執行緒在延遲指定時間之後可以週期性的執行執行緒體 * @param corePoolSize the number of threads to keep in the pool, * even if they are idle * @return a newly created scheduled thread pool 注意返回值型別是ScheduledExecutorService,不要使用ExecutorService來接收,否則找不到schedule執行方法 * @throws IllegalArgumentException if {@code corePoolSize < 0} */ public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize); //可自定義ThreadFactory public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize, ThreadFactory threadFactory);
/** * Creates an Executor that uses a single worker thread operating off an unbounded queue. *建立一個Executor,使用一個執行緒來工作,該執行緒儲存在LinkedBlockingQueue中 * (Note however that if this single thread terminates due to a failure during execution prior to shutdown, a new one will take its place if needed to execute subsequent tasks.) *注,如果任何執行緒正常關閉之前在執行過程中因失敗而提前終止,那麼如果有未被執行的後續任務,則會建立新的執行緒來繼續執行。 * Tasks are guaranteed to execute sequentially, and no more than one task will be active at any given time. * 任務是按順序執行的,任何時間都只有一個執行緒來執行任務 * Unlike the otherwise equivalent {@code newFixedThreadPool(1)} the returned executor is guaranteed not to be reconfigurable to use additional threads. * * @return the newly created single-threaded Executor */ public static ExecutorService newSingleThreadExecutor(); //可自定義ThreadFactory public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory);
/** * Creates a single-threaded executor that can schedule commands * to run after a given delay, or to execute periodically. * (Note however that if this single * thread terminates due to a failure during execution prior to * shutdown, a new one will take its place if needed to execute * subsequent tasks.) Tasks are guaranteed to execute * sequentially, and no more than one task will be active at any * given time. Unlike the otherwise equivalent * {@code newScheduledThreadPool(1)} the returned executor is * guaranteed not to be reconfigurable to use additional threads. * @return the newly created scheduled executor */ public static ScheduledExecutorService newSingleThreadScheduledExecutor(); public static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory threadFactory)
使用示例:
package thread.blogs.threadpool; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; /** * Created by PerkinsZhu on 2017/8/31 13:59. */ public class PoolTest { public static void main(String[] args) { // testCachedThreadPool(); // testSingleThreadExecutor(); // testFixedThreadPool(); testScheduledThreadPool(); } private static ThreadFactory myFactory = new MyThreadFactory(); private static void testSingleThreadExecutor() { //一個一個的依次執行 doHandle(Executors.newSingleThreadExecutor(myFactory)); } private static void testFixedThreadPool() { //兩個兩個的一起執行 doHandle(Executors.newFixedThreadPool(2,myFactory)); } private static void testCachedThreadPool() { //10個一起一次性執行完 doHandle(Executors.newCachedThreadPool(myFactory)); } private static void testScheduledThreadPool() { //定時週期執行 Executors.newScheduledThreadPool(1,myFactory).scheduleAtFixedRate(runnable, 500, 2000, TimeUnit.MILLISECONDS); } private static Runnable runnable = () -> { sleep(1000); System.out.println(Thread.currentThread().getName() + " work!!!"); }; private static void doHandle(ExecutorService executorService) { for (int i = 0; i < 10; i++) { executorService.execute(runnable); } executorService.shutdown(); } private static void sleep(int time) { try { Thread.sleep(time); } catch (InterruptedException e) { e.printStackTrace(); } } } class MyThreadFactory implements ThreadFactory {//自定義ThreadFactory private static final AtomicInteger poolNumber = new AtomicInteger(1); private final ThreadGroup group; private final AtomicInteger threadNumber = new AtomicInteger(1); private final String namePrefix; MyThreadFactory() { SecurityManager s = System.getSecurityManager(); group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup(); namePrefix = "☆☆☆--" + poolNumber.getAndIncrement() + "-****-"; } public Thread newThread(Runnable r) { Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0); if (t.isDaemon()) { t.setDaemon(false); } if (t.getPriority() != Thread.NORM_PRIORITY) { t.setPriority(Thread.NORM_PRIORITY); } return t; } }
在使用的時候必須明白各種執行緒池是否適用於自己的情景,選取合適的執行緒池進行使用。
=========================================
原文連結:多執行緒(七)JDK原生執行緒池轉載請註明出處!
=========================================