1. 程式人生 > >jdk單例執行緒池和sping執行緒池使用

jdk單例執行緒池和sping執行緒池使用

 java提供的原生執行緒池技術處理原理很清晰,故只要使用自己的原生執行緒池技術一般都能滿足專案的需求。java提供了很好的執行緒池實現,比我們自己的實現要更加健壯以及高效,同時功能也更加強大,不建議自己編寫。另外有同學可能用過spring的執行緒池,那麼spring執行緒池和jdk原生執行緒池有啥區別嗎?我們檢視原始碼和官方api可以知道SpringFrameWork 的 ThreadPoolTaskExecutor 是輔助 JDK 的 ThreadPoolExecutor 的工具類,它將屬性通過 JavaBeans 的命名規則提供出來,方便進行配置。也就是說spring的包裝了一下jdk,其實底層都是jdk的執行緒池。如果專案中有spring框架,建議使用spring的執行緒池(畢竟和環境一起,執行緒池的生命週期可以讓spring容器來管理,當然啦,也可以使用原生的jdk執行緒池),如果沒有其他要求,建議使用原生jdk執行緒池。

阿里巴巴的程式設計規範建議也是有異曲同工之妙的說法:

【強制】執行緒資源必須通過執行緒池提供,不允許在應用中自行顯式建立執行緒。
說明:使用執行緒池的好處是減少在建立和銷燬執行緒上所花的時間以及系統資源的開銷,解決資源不足的問題。如果不使用執行緒池,有可能造成系統建立大量同類執行緒而導致消耗完記憶體或者“過度切換”的問題。

1、原生jdk執行緒池單例使用

import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 執行緒池管理(執行緒統一排程管理)
 */
public final class ThreadPoolManager {

	private static ThreadPoolManager sThreadPoolManager = new ThreadPoolManager();

	// 執行緒池維護執行緒的最少數量
	private static final int SIZE_CORE_POOL = 15;

	// 執行緒池維護執行緒的最大數量
	private static final int SIZE_MAX_POOL = 15;

	/*
	 * 執行緒池單例建立方法
	 */
	public static ThreadPoolManager newInstance() {
		return sThreadPoolManager;
	}

	/**************************************************************************************************************
	 * 常見的幾種執行緒技術
	 ************************************************************************************************************** 
	 * Java通過Executors提供四種執行緒池,分別為:
	 * newCachedThreadPool建立一個可快取執行緒池,如果執行緒池長度超過處理需要,可靈活回收空閒執行緒,若無可回收,則新建執行緒。
	 * newFixedThreadPool 建立一個定長執行緒池,可控制執行緒最大併發數,超出的執行緒會在佇列中等待。
	 * newScheduledThreadPool 建立一個定長執行緒池,支援定時及週期性任務執行。 newSingleThreadExecutor
	 * 建立一個單執行緒化的執行緒池,它只會用唯一的工作執行緒來執行任務,保證所有任務按照指定順序(FIFO, LIFO, 優先順序)執行。
	 *
	 * 1、public static ExecutorService newFixedThreadPool(int nThreads) { 
	 * return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); }
	 * 
	 * 2、 public static ExecutorService newSingleThreadExecutor() { 
	 * return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())); } 
	 * 
	 * 3、public static ExecutorService newCachedThreadPool() { 
	 * return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); }
	 ****************************************************************************************************************/

	/**
	 * 執行緒池
	 * @param corePoolSize - 池中所儲存的執行緒數,包括空閒執行緒。
	 * @param maximumPoolSize - 池中允許的最大執行緒數。
	 * @param keepAliveTime - 當執行緒數大於核心時,此為終止前多餘的空閒執行緒等待新任務的最長時間。
	 * @param unit - keepAliveTime 引數的時間單位。
	 * @param workQueue - 執行前用於保持任務的佇列。此佇列僅由保持 execute 方法提交的 Runnable 任務。
	 * @param handler - 由於超出執行緒範圍和佇列容量而使執行被阻塞時所使用的處理程式。
	 */
	// 實質就是newFixedThreadPool 建立一個定長執行緒池,可控制執行緒最大併發數,超出的執行緒會在佇列中等待
	private final ThreadPoolExecutor mThreadPool = new ThreadPoolExecutor(SIZE_CORE_POOL, SIZE_MAX_POOL, 0L,
			TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
	
	/*
	 * 將構造方法訪問修飾符設為私有,禁止任意例項化。
	 */
	private ThreadPoolManager() {
	}

	/*
	 * 將執行緒池初始化,核心執行緒數量
	 */
	public void perpare() {
		if (mThreadPool.isShutdown() && !mThreadPool.prestartCoreThread()) {
			@SuppressWarnings("unused")
			int startThread = mThreadPool.prestartAllCoreThreads();
		}
	}

	/*
	 * 向執行緒池中新增任務方法
	 */
	public void addExecuteTask(Runnable task) {
		if (task != null) {
			mThreadPool.execute(task);
		}
	}

	/*
	 * 判斷是否是最後一個任務
	 */
	protected boolean isTaskEnd() {
		if (mThreadPool.getActiveCount() == 0) {
			return true;
		} else {
			return false;
		}
	}
	
	/*
	 * 獲取快取大小
	 */
	public int getQueue(){
		return mThreadPool.getQueue().size();
	}
	
	/*
	 * 獲取執行緒池中的執行緒數目
	 */
	public int getPoolSize(){
		return mThreadPool.getPoolSize();
	}
	
	/*
	 * 獲取已完成的任務數
	 */
	public long getCompletedTaskCount(){
		return mThreadPool.getCompletedTaskCount();
	}
	
	/*
	 * 關閉執行緒池,不在接受新的任務,會把已接受的任務執行玩
	 */
	public void shutdown() {
		mThreadPool.shutdown();
	}
}
新增任務的時候,可以自定義任務,只要實現Runnable介面的類就行~ 
public class TestThreadPool {

	/**
	 * @Name: main
	 * @Description: TODO(這裡用一句話描述這個類的作用)
	 * @Author: tjf
	 * @Version: V1.00
	 * @CreateDate: 2016年10月18日上午11:44:35
	 * @param args
	 * @Return: void 返回型別
	 */
	public static void main(String[] args) {

		ThreadPoolManager threadPoolManager = ThreadPoolManager.newInstance();
		for (int i = 0; i < 100; i++) {
			threadPoolManager.addExecuteTask(new MyTask(i));
			System.out.println("執行緒池中執行緒數目:" + threadPoolManager.getPoolSize() + ",佇列中等待執行的任務數目:"
					+ threadPoolManager.getQueue() + ",已執行玩別的任務數目:" + threadPoolManager.getCompletedTaskCount());
		}
		threadPoolManager.shutdown();
	}

}

class MyTask implements Runnable {
	private int taskNum;

	public MyTask(int taskNum) {
		this.taskNum = taskNum;
		;
	}

	@SuppressWarnings("static-access")
	public void run() {
		System.out.println("正在執行task " + taskNum);
		try {
			Thread.currentThread().sleep(4000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("task " + taskNum + "執行完畢");
	}

	public int getTaskNum() {
		return taskNum;
	}

	public void setTaskNum(int taskNum) {
		this.taskNum = taskNum;
	}

2、spring執行緒池的配置

<!-- 非同步執行緒池 -->
    <bean id="threadPool"
        class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
        <!-- 核心執行緒數 -->
        <property name="corePoolSize" value="3" />
        <!-- 最大執行緒數 -->
        <property name="maxPoolSize" value="10" />
        <!-- 佇列最大長度 >=mainExecutor.maxSize -->
        <property name="queueCapacity" value="25" />
        <!-- 執行緒池維護執行緒所允許的空閒時間 -->
        <property name="keepAliveSeconds" value="300" />
        <!-- 執行緒池對拒絕任務(無執行緒可用)的處理策略 ThreadPoolExecutor.CallerRunsPolicy策略 ,呼叫者的執行緒會執行該任務,如果執行器已關閉,則丟棄.  -->
        <property name="rejectedExecutionHandler">
            <bean class="java.util.concurrent.ThreadPoolExecutor$CallerRunsPolicy" />
        </property>
    </bean>

其實就是將jdk執行緒池進行配置化,宣告週期由spring容器管理。其他的關鍵屬性和關鍵方法都和jdk執行緒池如出一轍。