1. 程式人生 > >Java多執行緒-執行緒池Executors

Java多執行緒-執行緒池Executors

概覽

通過上一篇對ThreadPoolExecutor的構造方法分析可以感受到,通過ThreadPoolExecutor來建立執行緒池是比較複雜的,引數比較多,考慮因素也多。

因此java自己提供了一個工廠類Executors,裡面提供了一些方法,用來建立常用的幾種ThreadPoolExecutor執行緒池。

下面是方法概覽:

public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0
L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); } public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new
SynchronousQueue<Runnable>()); } public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new
LinkedBlockingQueue<Runnable>())); } public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) { return new ScheduledThreadPoolExecutor(corePoolSize); }

分析

FixedThreadPool

FixedThreadPool呼叫的是ThreadPoolExecutor的構造方法。有下面兩種使用方式:

//不帶工廠的
public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
}
//帶工廠的
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>(),
                                      threadFactory);
    }

通過對ThreadPoolExecutor構造引數的分析可以看出來,這個執行緒池的最大執行緒數就是核心執行緒數,也就是沒有非核心執行緒的存在。這些執行緒都是核心執行緒,即使在閒置狀態也不會被回收,除非執行緒池關閉了,所以超時機制並沒有用。他的任務佇列是無界的LinkedBlockingQueue,因此超過核心執行緒數量的任務會放在佇列中排隊。

這樣的執行緒池優點很明顯,只會建立固定數量的執行緒,然後這些執行緒一直存活重用,不會有額外的建立和銷燬執行緒的開銷,能更快的執行任務。

測試

ExecutorService executor = Executors.newFixedThreadPool(2);
Runnable myRunnable = new Runnable() {
    @Override
    public void run() {
        try {
            Thread.sleep(2000);
            System.out.println(Thread.currentThread().getName() + " run time: "+System.currentTimeMillis());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
};
for (int i = 0; i < 6; i++) {
    executor.execute(myRunnable);
}

建立一個固定大小為2的FixedThreadPool,然後新增6個任務,輸出是:

pool-1-thread-2 run time: 1493863106021
pool-1-thread-1 run time: 1493863106021
pool-1-thread-2 run time: 1493863108022
pool-1-thread-1 run time: 1493863108022
pool-1-thread-1 run time: 1493863110026
pool-1-thread-2 run time: 1493863110027

可以看到這個執行緒池只會建立2個執行緒,其他的都在排隊。

執行緒工廠

public static void main(String[] args) throws InterruptedException {
     ExecutorService executor = Executors.newFixedThreadPool(2,new MyFactory());
     Runnable myRunnable = new Runnable() {
         @Override
         public void run() {
             try {
                 Thread.sleep(2000);
                 System.out.println(Thread.currentThread().getName() + " run time: "+System.currentTimeMillis());
             } catch (InterruptedException e) {
                 e.printStackTrace();
             }

         }
     };
     for (int i = 0; i < 6; i++) {
         executor.execute(myRunnable);
     }
 }

static class MyFactory implements ThreadFactory{

     @Override
     public Thread newThread(@NonNull Runnable r) {
         Thread thread = new Thread(r);
         thread.setName("哈哈"+ UUID.randomUUID().toString().substring(0,3));
         return thread;
     }
 }

建立一個工廠,自定義設定執行緒名字,然後在newFixedThreadPool時傳入工廠,看輸出

哈哈fea run time: 1493863498244
哈哈491 run time: 1493863498244
哈哈fea run time: 1493863500250
哈哈491 run time: 1493863500250
哈哈fea run time: 1493863502253
哈哈491 run time: 1493863502253

下面的工廠引數都是這樣,就不在寫了。

CachedThreadPool

CachedThreadPool也是用的ThreadPoolExecutor的構造方法

public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>());
}

public static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory threadFactory) {
        return new DelegatedScheduledExecutorService
            (new ScheduledThreadPoolExecutor(1, threadFactory));
}

分析這個引數可以看出,這個執行緒池沒有核心執行緒,所有的執行緒都會在限制60秒後被回收。而且最大執行緒數為Integer.MAX_VALUE,相當於無限大。因為任務佇列是SynchronousQueue,不會儲存任何任務,所以當有新任務時,如果當前執行緒都在活動著,就會新建一個執行緒來執行任務。

這樣的執行緒池的特點就是,適合執行大量的耗時短的任務。而且當所有任務執行完後,閒置超過60秒就會全部回收,這是執行緒池裡就沒有任何執行緒,不會佔用系統資源。

測試

ExecutorService executor = Executors.newCachedThreadPool();
        Runnable myRunnable = new Runnable() {
    @Override
    public void run() {
        try {
            Thread.sleep(2000);
            System.out.println(Thread.currentThread().getName() + " run time: "+System.currentTimeMillis());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
};
for (int i = 0; i < 3; i++) {
    executor.execute(myRunnable);
}
Thread.sleep(30000);
System.out.println("睡眠30秒後");
for (int i = 0; i < 3; i++) {
    executor.execute(myRunnable);
}
Thread.sleep(65000);
System.out.println("再睡眠65秒後");
for (int i = 0; i < 3; i++) {
    executor.execute(myRunnable);
}

先執行三個任務,30秒後再新增3個任務,再過65秒再新增3個任務。

pool-1-thread-1 run time: 1493864065635
pool-1-thread-2 run time: 1493864065635
pool-1-thread-3 run time: 1493864065639
睡眠30秒後
pool-1-thread-3 run time: 1493864095637
pool-1-thread-2 run time: 1493864095637
pool-1-thread-1 run time: 1493864095637
再睡眠65秒後
pool-1-thread-5 run time: 1493864160643
pool-1-thread-4 run time: 1493864160643
pool-1-thread-6 run time: 1493864160643

可以看到一開始建立了3個執行緒,30秒後重用了這三個執行緒。但是再過65秒後,者三個執行緒就因為超時被回收了,所以新建了三個執行緒。

SingleThreadExecutor

SingleThreadExecutor使用new FinalizableDelegatedExecutorService來建立執行緒池。但是其實通過一個委託呼叫了ThreadPoolExecutor的構造方法

public static ExecutorService newSingleThreadExecutor() {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(1, 1,
                                0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>()));
}

public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>(),
                                    threadFactory));
}

從ThreadPoolExecutor的構造引數依然可以看出,這個執行緒池僅有一個核心執行緒,其他的任務都在任務佇列中排隊。

這樣的執行緒池會讓所有的任務都在同一個執行緒中執行,避免的同步問題。

測試

ExecutorService executor = Executors.newSingleThreadExecutor();
        Runnable myRunnable = new Runnable() {
    @Override
    public void run() {
        try {
            Thread.sleep(2000);
            System.out.println(Thread.currentThread().getName() + " run time: "+System.currentTimeMillis());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
};
for (int i = 0; i < 3; i++) {
    executor.execute(myRunnable);
}

Thread.sleep(65000);
System.out.println("睡眠65秒後");
for (int i = 0; i < 3; i++) {
    executor.execute(myRunnable);
}
pool-1-thread-1 run time: 1493864476076
pool-1-thread-1 run time: 1493864478078
pool-1-thread-1 run time: 1493864480082
睡眠65秒後
pool-1-thread-1 run time: 1493864541080
pool-1-thread-1 run time: 1493864543083
pool-1-thread-1 run time: 1493864545087

自始至終都只有一個執行緒。而且不會被回收。

ScheduledThreadPool

ScheduledThreadPool使用new ScheduledThreadPoolExecutor來建立

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
    return new ScheduledThreadPoolExecutor(corePoolSize);
}

public static ScheduledExecutorService newScheduledThreadPool(
            int corePoolSize, ThreadFactory threadFactory) {
        return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);
}

看一下具體使用的構造引數:

public ScheduledThreadPoolExecutor(int corePoolSize,
                                   ThreadFactory threadFactory) {
    super(corePoolSize, Integer.MAX_VALUE,
          DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
          new DelayedWorkQueue(), threadFactory);
}

可以看到,這個執行緒池的核心執行緒數是固定的,但是匯流排程數是無限的,然而因為DelayedWorkQueue是個無界佇列,所以這個值沒有意義,超過核心執行緒的任務都會放在佇列中。

ScheduledThreadPoolExecutor主要是用來執行定時任務和有周期性的重複任務。

這裡就舉個不恰當的例子,不是ScheduledThreadPoolExecutor的用法

ExecutorService executor = Executors.newScheduledThreadPool(3);
        Runnable myRunnable = new Runnable() {
    @Override
    public void run() {
        try {
            Thread.sleep(2000);
            System.out.println(Thread.currentThread().getName() + " run time: "+System.currentTimeMillis());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
};
for (int i = 0; i < 6; i++) {
    executor.execute(myRunnable);
}
pool-1-thread-3 run time: 1493866372444
pool-1-thread-1 run time: 1493866372444
pool-1-thread-2 run time: 1493866372444
pool-1-thread-2 run time: 1493866374450
pool-1-thread-1 run time: 1493866374450
pool-1-thread-3 run time: 1493866374450

設定的是3,就只會建立3個執行緒。

相關推薦

跟我學Java線程——線程與堵塞隊列

信號 線程的創建 margin cit rect weight offer 成功 rain 前言 上一篇文章中我們將ThreadPoolExecutor進行了深入的學習和介紹,實際上我們在項目中應用的時候非常少有直接應用ThreadPoolExecutor來

Java線程-線程ThreadPoolExecutor構造方法和規則

解決 $1 核心 keepaliv 狀態 被拒絕 live link 限時 為什麽用線程池 博客地址 http://blog.csdn.net/qq_25806863 原文地址 http://blog.csdn.net/qq_25806863/article/details

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

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

Java執行-執行Executors

概覽 通過上一篇對ThreadPoolExecutor的構造方法分析可以感受到,通過ThreadPoolExecutor來建立執行緒池是比較複雜的,引數比較多,考慮因素也多。 因此java自己提供了一個工廠類Executors,裡面提供了一些方法,用

Java執行三:執行Executors類解析

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

JAVA執行(三) 執行和鎖的深度化

 github演示程式碼地址:https://github.com/showkawa/springBoot_2017/tree/master/spb-demo/src/main/java/com/kawa/thread 1.執行緒池  1.1 執行緒池是什麼 Java中的執行緒

java執行7.使用執行

只有當任務都是同類型並且相互獨立時,執行緒池的效能才能達到最佳。如果將執行時間較長的與執行時間較短的任務混合在一起,那麼除非執行緒池很大,否則將可能造成擁塞,如果提交的任務依賴於其他任務,那麼除非執行緒池無線大,否則將可能造成死鎖。 例如飢餓死鎖:執行緒池中的任務需要無限等待一些必須由池中其他任務才能提供的

Java執行 - 執行 ThreadPoolExecutor類的使用

ThreadPoolExecutor類可以非常方便的建立執行緒池物件,而不需要程式設計師設計大量的new去例項化Thread相關的程式碼 最常用的構造方法 (不過threadFactory可以視情況設或不設) ThreadPoolExecutor(   &nb

Java執行執行狀態、執行狀態

執行緒狀態:     執行緒共包括以下5種狀態。1. 新建狀態(New)  執行緒物件被建立後,就進入了新建狀態。例如,Thread thread = new Thread()。2. 就緒狀態(Runnable)  也被稱為“可執行狀態”。執行緒物件被建立後,

Java執行-併發之執行

執行緒池有了解嗎? 答: java.util.concurrent.ThreadPoolExecutor 類就是一個執行緒池。客戶端呼叫ThreadPoolExecutor.submit(Runnable task) 提交任務,執行緒池內部維護的工作者執行緒的數量就是該執行緒池的執行

Java執行(ExecutorService 、Executors、Callable、Future、FutureTask)

前言:我們一般通過繼承Thread類重寫run方法或者實現runnable介面重寫run方法,最後建立和啟動一個執行緒,但是都需要自己建立、啟動Thread物件。執行緒池可以實現幫助我們管理Thread物件,至於要使用幾個執行緒,什麼時候啟動這些執行緒,是開啟多個執行緒還是用單個執行緒來完成

Java執行使用執行實現檔案下載

多執行緒下載原理: 1、基本思路是將檔案分段切割、分段傳輸、分段儲存。 2、分段切割用到HttpUrlConnection物件的setRequestProperty(“Range”, “bytes=” + start + “-” + end)方法。 3、分段傳輸用到HttpU

Java——執行基本使用(四) 執行組和執行的使用,工廠設計模式的使用

1.執行緒組的概述和使用 Java中使用ThreadGroup來表示執行緒組,它可以對一批執行緒進行分類管理,Java允許程式直接對執行緒組進行控制。            &n

Java執行-執行ThreadPoolExecutor構造方法和規則 Java執行-執行ThreadPoolExecutor構造方法和規則

Java多執行緒-執行緒池ThreadPoolExecutor構造方法和規則 2017年05月03日 17:15:37 閱讀數:40542 為什麼用執行緒池 部落格地址 http://blog.csdn.ne

Java執行程式設計實戰》—— 第9章 Thread Pool(執行)模式

一個系統中的執行緒相對於其所要處理的任務而言,是一種非常有限的資源。執行緒不僅在執行任務時需要消耗CPU時間和記憶體等資源,執行緒物件(Thread例項)本身以及執行緒所需的呼叫棧(Call Stack)也佔用記憶體,並且Java中建立一個執行緒往往意味著JVM會建立相應的依賴於宿主機作業系

(CSDN遷移)JAVA執行實現-單執行執行newSingleThreadExecutor

JAVA通過Executors提供了四種執行緒池,單執行緒化執行緒池(newSingleThreadExecutor)、可控最大併發數執行緒池(newFixedThreadPool)、可回收快取執行緒池(newCachedThreadPool)、支援定時與週期性任務的執行緒池(newScheduledThre

(CSDN遷移) JAVA執行實現-可控最大併發數執行(newFixedThreadPool)

上篇文章中介紹了單執行緒化執行緒池newSingleThreadExecutor,可控最大併發數執行緒池(newFixedThreadPool)與其最大的區別是可以通知執行多個執行緒,可以簡單的將newSingleThreadExecutor理解為newFixedThreadPool(1)。例如執行一下兩個程

java執行(13)執行

當程式中需要大量並且生存週期很短的執行緒時候,可以考慮使用執行緒池,執行緒池的工作原理是線上程池創立的時候就建立大量空閒的執行緒,當一個Runnable或者Callable物件傳到執行緒池的時候,執行緒池就啟動一執行緒來執行他們的run或者call方法,當run或者call方

Java執行2.8.執行2

執行緒池 1、實現Callable介面來實現執行緒池 Callable:是帶泛型的介面。 這裡指定的泛型其實是call()方法的返回值型別。 (1)建立實現Callable類的執行緒類 pa

Java執行系列--“JUC執行”01之 執行架構

概要 前面分別介紹了”Java多執行緒基礎”、”JUC原子類”和”JUC鎖”。本章介紹JUC的最後一部分的內容——執行緒池。內容包括: 執行緒池架構圖 執行緒池示例 執行緒池架構圖 執行緒池的架構圖如下: 1、Executor