1. 程式人生 > >淺析Java中的四種執行緒池

淺析Java中的四種執行緒池

1.使用執行緒池的好處

  

2.JUC中幾種常用的執行緒池

java.util.concurrent包下的Executors工廠類,提供了一系列的執行緒池的建立方法,其構造方法如下:

public ThreadPoolExecutor(int corePoolSize,              //執行緒池執行緒核心數量,執行緒池維護執行緒的最少數量
                              int maximumPoolSize,               //執行緒池最大執行緒數量
                              long keepAliveTime,           //空閒執行緒存活時間
                              TimeUnit unit,              //存活時間的時間單位
                              BlockingQueue<Runnable> workQueue,  //儲存任務的執行緒佇列
                              ThreadFactory threadFactory,      //執行緒工廠
                              RejectedExecutionHandler handler) {   //拒絕策略
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

其中常用的執行緒池有四種,分別是fixedThreadPool、cachedThreadPool、ScheduledThreadPool和SingleThreadExecutor。他們分別適用在不同的場合。

2.1  newFixedThreadPool

特點:

    • 用於建立一個可重用、固定執行緒數量的執行緒池;
    • 當執行緒池中執行緒都處於執行中時,新來的執行緒會進入等待狀態,直到執行緒池中出現一個空閒執行緒;
    • 當一個執行緒在任務中途退出、終止時,會有一個新的執行緒來替代它繼續完成後面未完成的任務。
    • 除非採用顯式關閉的方法去關閉某個執行緒,否則執行緒會一直存在,不會釋放資源。
    • 任務儲存在無界阻塞佇列中
    • 適用場景:長期任務

構造方法:

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

例項程式碼:  

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.junit.Test;

public class ExecutorsTest extends Thread{
    private int index;
    public ExecutorsTest(int i) 
    {
        this.index = i;
    }
    
    public void run() 
    {
        try 
        {
            System.out.println("[Thread"+this.index+"]" +"start..");
            Thread.sleep((int)(Math.random()*10000));
            System.out.println("[Thread"+this.index+"]" + "end");
        }catch(Exception e) 
        {
            e.printStackTrace();
        }
    }
            
        
    public static void main(String args[]) 
    {
        ExecutorService service = Executors.newFixedThreadPool(4);
        
        for(int i=0;i<10;i++) 
        {
            service.execute(new ExecutorsTest(i));
        }
        service.shutdown();    
        
    }
}

因為執行緒池中執行緒數量一共有4個,所以當一次有大於4個的任務需要執行時,因為執行緒池中無空閒執行緒,後續任務進入等待狀態,當其他任務執行完畢後,執行緒空閒,則馬上開始執行正在等待的任務。

 

2.1  newCachedThreadPool

特點:

  • 執行緒池數量上限為:Integer.MaxValue(2147483647);
  • 執行緒池預設空閒60S,超過60S會從執行緒池中移除;
  • 新來任務時,先檢查是否有空閒執行緒可使用,若無,則建立一個新執行緒執行任務;
  • 任務儲存在同步佇列中。
  • 適用場景:短時非同步任務。

建構函式:

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

示例程式碼:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.junit.Test;

public class ExecutorsTest extends Thread{
    private int index;
    public ExecutorsTest(int i) 
    {
        this.index = i;
    }
    
    public void run() 
    {
        try 
        {
            System.out.println("[Thread"+this.index+"]" +"start..");
            Thread.sleep((int)(Math.random()*1000));
            System.out.println("[Thread"+this.index+"]" + "end");
        }catch(Exception e) 
        {
            e.printStackTrace();
        }
    }
            
        
    
    public static void main(String args[]) 
    {
        ExecutorService service = Executors.newCachedThreadPool();
        
        for(int i=0;i<10;i++) 
        {
            service.execute(new ExecutorsTest(i));
        }
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
        for(int i=0;i<5;i++) 
        {
            service.execute(new ExecutorsTest(i));
        }
        
        service.shutdown();    
        
    }

 建立10個工作執行緒用於處理任務,當執行緒執行完畢後,處於空閒狀態,此時若出現新的任務,則會從執行緒池中用空閒的執行緒來處理新的任務。若沒有空閒執行緒,則開啟新執行緒處理。

2.3  newSingleThreadExecutor

特點:

  • 建立一個單個Worker的執行緒;
  • 執行緒會按照順序依次執行;
  • 任務儲存在無界阻塞佇列中
  • 適用場景:需要按照順序執行的任務。

構造方法:

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

 例項程式碼:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.junit.Test;

public class ExecutorsTest extends Thread{
    private int index;
    public ExecutorsTest(int i) 
    {
        this.index = i;
    }
    
    public void run() 
    {
        try 
        {
            System.out.println("[Thread"+this.index+"]" +"start..");
            Thread.sleep((int)(Math.random()*1000));
            System.out.println("[Thread"+this.index+"]" + "end");
        }catch(Exception e) 
        {
            e.printStackTrace();
        }
    }
            
    public static void main(String args[]) 
    {
        ExecutorService service = Executors.newSingleThreadExecutor();
        
        for(int i=0;i<10;i++) 
        {
            service.execute(new ExecutorsTest(i));
        }
        service.shutdown();    
        
    }

}

 出現多個任務時,SingleThreadExecutor會按照順序依次執行各個任務。

2.4 newScheduledThreadPool

 特點:

  • 任務儲存在無界延遲佇列中
  • 適用場景:需要定期執行或延遲執行的任務

構造方法:

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

    public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue());
    }

例項程式碼一(scheduleAtFixedRate的使用)

import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class ExecutorsTest2 extends Thread{
    private int index;
    public ExecutorsTest2() 
    {
    }
    
    public void run() 
    {
        try 
        {
            System.out.println("[Current Time is "+new Date().toString());
            
        }catch(Exception e) 
        {
            e.printStackTrace();
        }
    }
                
    public static void main(String args[]) 
    {
        /*
         * 執行定時任務newScheduledThreadPool
         */
        ScheduledExecutorService service = Executors.newScheduledThreadPool(10);
        
        //5秒後開始執行,每隔一秒執行一次
        service.scheduleAtFixedRate(new ExecutorsTest2(), 5, 1, TimeUnit.SECONDS);
    }
}

scheduleAtFixedRate方法,一共四個引數,分別是:需要執行的任務task、延遲執行時間t1、每次執行任務的時間間隔t2、時間間隔單位。
含義是:在t1時間過後,以 1次/t2 的頻率來不斷執行 task。
上述程式碼中,在5秒延遲後,以 1次/1秒的頻率執行 列印當前時間的任務。

例項程式碼二scheduleWithFixedDelay的使用):

import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class ExecutorsTest3 extends Thread{
    private int index;
    public ExecutorsTest3() 
    {
    }
    
    public void run() 
    {
        try 
        {
            //每次任務大約耗時1秒
            Thread.sleep(1000);
            System.out.println("[Current Time is "+new Date().toString());
            
        }catch(Exception e) 
        {
            e.printStackTrace();
        }
    }
                
    public static void main(String args[]) 
    {
        /*
         * 執行定時任務newScheduledThreadPool
         */
        ScheduledExecutorService service = Executors.newScheduledThreadPool(10);
        
        //5秒後開始執行,每次任務執行完後延遲3秒後,繼續執行下一次
        service.scheduleWithFixedDelay(new ExecutorsTest3(), 5, 3, TimeUnit.SECONDS);
    }
}

scheduleWithFixedDelay也是四個引數,分別是:待執行的任務Task,延遲時間t1,每次任務執行完畢後延遲t2秒後執行下次任務,延遲時間單位。

我有一個微信公眾號,經常會分享一些Java技術相關的乾貨;如果你喜歡我的分享,可以用微信搜尋“Java團長”或者“javatuanzhang”關注。