1. 程式人生 > >JAVA執行緒池--Executors之什麼是執行緒池,為什麼使用執行緒池以及執行緒池的使用

JAVA執行緒池--Executors之什麼是執行緒池,為什麼使用執行緒池以及執行緒池的使用

1. 為什麼需要執行緒池?

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

        如果:T1 + T3 遠大於 T2,則可以採用執行緒池,以提高伺服器效能。

        執行緒池技術正是關注如何縮短或調整T1,T3時間的技術,從而提高伺服器程式效能的。它把T1,T3分別安排在伺服器程式的啟動和結束的時間段或者一些空閒的時間段,這樣在伺服器程式處理客戶請求時,不會有T1,T3的開銷了。
        執行緒池不僅調整T1,T3產生的時間段,而且它還顯著減少了建立執行緒的數目,看一個例子:
       假設一個伺服器一天要處理50000個請求,並且每個請求需要一個單獨的執行緒完成。線上程池中,執行緒數一般是固定的,所以產生執行緒總數不會超過執行緒池中執行緒的數目,而如果伺服器不利用執行緒池來處理這些請求則執行緒總數為50000。一般執行緒池大小是遠小於50000。所以利用執行緒池的伺服器程式不會為了建立50000而在處理請求時浪費時間,從而提高效率。

   一個執行緒池包括以下四個基本組成部分:
                1、執行緒池管理器(ThreadPool):用於建立並管理執行緒池,包括 建立執行緒池,銷燬執行緒池,新增新任務;
                2、工作執行緒(PoolWorker):執行緒池中執行緒,在沒有任務時處於等待狀態,可以迴圈的執行任務;
                3、任務介面(Task):每個任務必須實現的介面,以供工作執行緒排程任務的執行,它主要規定了任務的入口,任務執行完後的收尾工作,任務的執行狀態等;
                4、任務佇列(taskQueue):用於存放沒有處理的任務。提供一種緩衝機制。

執行緒池的作用總結為:

1.減少了建立和銷燬執行緒的次數,每個工作執行緒都可以被重複利用,可執行多個任務。

2.可以根據系統的承受能力,調整執行緒池中工作線執行緒的數目,防止因為消耗過多的記憶體,而把伺服器累趴下(每個執行緒需要大約1MB記憶體,執行緒開的越多,消耗的記憶體也就越大,最後宕機)。

2. 什麼是執行緒池?

   答:java.util.concurrent.Executors提供了一個 java.util.concurrent.Executor介面的實現用於建立執行緒池

3. 執行緒池怎麼使用?

Java裡面執行緒池的頂級介面是Executor,但是嚴格意義上講Executor並不是一個執行緒池,而只是一個執行執行緒的工具。真正的執行緒池介面是ExecutorService。

比較重要的幾個類:

ExecutorService

真正的執行緒池介面。

ScheduledExecutorService

能和Timer/TimerTask類似,解決那些需要任務重複執行的問題。

ThreadPoolExecutor

ExecutorService的預設實現。

ScheduledThreadPoolExecutor

繼承ThreadPoolExecutor的ScheduledExecutorService介面實現,週期性任務排程的類實現。

Executors提供四種執行緒池,分別為:
newCachedThreadPool建立一個可快取執行緒池,如果執行緒池長度超過處理需要,可靈活回收空閒執行緒,若無可回收,則新建執行緒。當執行緒池大小超過了處理任務所需的執行緒,那麼就會回收部分空閒(一般是60秒無執行)的執行緒,當有任務來時,又智慧的新增新執行緒來執行。
newFixedThreadPool 建立一個定長執行緒池,可控制執行緒最大併發數,超出的執行緒會在佇列中等待。
newScheduledThreadPool 建立一個定長執行緒池,支援定時及週期性任務執行。
newSingleThreadExecutor 建立一個單執行緒化的執行緒池,它只會用唯一的工作執行緒來執行任務,保證所有任務按照指定順序(FIFO, LIFO, 優先順序)執行。

注意:執行緒池只是為了控制應用中處理某項業務中防止高併發問題帶來的執行緒不安全的發生的概率。在我目前的測試用,還沒有發現執行緒可以重用這個概念,因為執行緒開啟後,用完就關閉了,不可以再次開啟的,檢視原始碼發現會每次新建立一個執行緒用來處理業務。我們可以通過執行緒池指定處理這項業務最大的同步執行緒數,比如:Executors.newFixedThreadPool(3);線上程池中保持三個執行緒可以同時執行,但是注意,並不是說執行緒池中永遠都是這三個執行緒,只是說可以同時存在的執行緒數,當某個執行緒執行結束後,會有新的執行緒進來。newFixedThreadPool.execute(newThreadForpools());這句話的含義並不是新增新的執行緒,而是新增新的處理業務請求進來。至少我當前是這麼理解的,沒有發現執行緒可以重複使用。

處理執行緒程式碼:

package com.alivn.sockets;
/**
 * Created by Alivn on 2017/3/19.
 */
public class ThreadForpools implements Runnable{

    private Integer index;
    public  ThreadForpools(Integer index)
    {
     this.index=index;
    }
    @Override
    public void run() {
        /***
         * 業務......省略
          */
        try {
            System.out.println("開始處理執行緒!!!");
            Thread.sleep(index*100);
            System.out.println("我的執行緒標識是:"+this.toString());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

(1) newCachedThreadPool
建立一個可快取執行緒池,應用中存在的執行緒數可以無限大

示例程式碼如下:

package com.alivn.sockets;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Created by Alivn on 2017/3/19.
*/
public class Threadpools {

/**
* 我們獲取四次次執行緒,觀察4個執行緒地址
* @param args
*/
public static void main(String[]args)
{
ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();
System.out.println("****************************newCachedThreadPool*******************************");
for(int i=0;i<4;i++)
{
final int index=i;
newCachedThreadPool.execute(new ThreadForpools(index));
}
}
}

輸出結果是:可以有無限大的執行緒數進來(執行緒地址不一樣)

111111

(2) newFixedThreadPool
建立一個定長執行緒池,可控制執行緒最大併發數,超出的執行緒會在佇列中等待。示例程式碼如下:

Package com.alivn.sockets;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Created by Alivn on 2017/3/19.
*/
public class Threadpools {

/**
* 我們獲取四次次執行緒,觀察4個執行緒地址
* @param args
*/
public static void main(String[]args)
{
//執行緒池允許同時存在兩個執行緒
ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(2);
System.out.println("****************************newFixedThreadPool*******************************");
for(int i=0;i<4;i++)
{
final int index=i;
newFixedThreadPool.execute(new ThreadForpools(index));
}
}
}

輸出結果:每次只有兩個執行緒在處理,當第一個執行緒執行完畢後,新的執行緒進來開始處理(執行緒地址不一樣)

222

(3)  newScheduledThreadPool
建立一個定長執行緒池,支援定時及週期性任務執行。延遲執行示例程式碼如下:

package com.alivn.sockets;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
* Created by Alivn on 2017/3/19.
*/
public class Threadpools {

/**
* 我們獲取四次次執行緒,觀察4個執行緒地址
* @param args
*/
public static void main(String[]args)
{
ScheduledExecutorService newScheduledThreadPool = Executors.newScheduledThreadPool(2);
System.out.println("****************************newFixedThreadPool*******************************");
for(int i=0;i<4;i++)
{
final int index=i;
//延遲三秒執行
newScheduledThreadPool.schedule(new ThreadForpools(index),3, TimeUnit.SECONDS);
}
}
}

執行結果:延遲三秒之後執行,除了延遲執行之外和newFixedThreadPool基本相同,可以用來執行定時任務

333

4) newSingleThreadExecutor
建立一個單執行緒化的執行緒池,它只會用唯一的工作執行緒來執行任務,保證所有任務按照指定順序(FIFO, LIFO, 優先順序)執行。示例程式碼如下:

package com.alivn.sockets;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
* Created by Alivn on 2017/3/19.
*/
public class Threadpools {

/**
* 我們獲取四次次執行緒,觀察4個執行緒地址
* @param args
*/
public static void main(String[]args)
{
ExecutorService newSingleThreadExecutor = Executors.newSingleThreadExecutor();
System.out.println("****************************newFixedThreadPool*******************************");
for(int i=0;i<4;i++)
{
final int index=i;
newSingleThreadExecutor.execute(new ThreadForpools(index));
}
}
}

執行結果:只存在一個執行緒,順序執行

444

轉載於:https://www.cnblogs.com/ljp-sun/p/6580147.html