juc - 線程池的使用

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.*;

/**
 * @description: 測試使用線程池
 */
public class TestThreadPool {

	public static void main(String[] args) {
		//核心線程個數
		int corePoolSize = 2;
		//最大線程數量
		int maximumPoolSize = 4;
		//創建了超出核心線程個數的線程(臨時線程)後,當該線程空閒下來可能會被銷燬
		//線程允許空閒時間(線程在空閒狀態下,在允許空閒時間內不會銷燬)
		//TimeUnit表示允許線程空閒時間的單位
		long keepAliveTime = 1L;
		//等待隊列
		BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(1024);
		//線程池飽和策略
		RejectedExecutionHandler policy = new RejectedDiscardPolicy("taskId");
		ExecutorService executor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit.SECONDS, queue, policy);
		for (int i = 0; i < 100000; i++) {
			executor.execute(new Worker());
		}

		//慎用shutdownNow(立即關閉線程池,不管隊列中的任務是否執行完)
//		executorService.shutdownNow();
		//推薦使用shutdown去關閉線程池,這個方法會等待隊列中的任務全部執行完纔去關閉線程池
		executor.shutdown();
	}


}

class Worker implements Runnable {

	@Override
	public void run() {
		System.out.println(Thread.currentThread().getName() + "正在執行");
	}
}


/**
 * @description: 自定義飽和策略(中止策略也是默認策略)
 */
class RejectedAbortPolicy implements RejectedExecutionHandler {
	/**
	 * 執行任務的標識
	 */
	private String taskId;

	public String getTaskId() {
		return taskId;
	}

	public void setTaskId(String taskId) {
		this.taskId = taskId;
	}

	public RejectedAbortPolicy(String taskId) {
		this.taskId = taskId;
	}

	/**
	 * @description: 使用該策略時在飽和時會拋出RejectedExecutionException(繼承自RuntimeException),調用者可捕獲該異常自行處理。
	 */
	@Override
	public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
		throw new RejectedExecutionException(taskId +
				" rejected from " +
				executor.toString());
	}
}

/**
 * @description: 自定義飽和策略(拋棄策略)
 */
class RejectedDiscardPolicy implements RejectedExecutionHandler {
	protected Logger logger = LoggerFactory.getLogger(this.getClass());
	/**
	 * 執行任務的標識
	 */
	private String taskId;

	public String getTaskId() {
		return taskId;
	}

	public void setTaskId(String taskId) {
		this.taskId = taskId;
	}

	public RejectedDiscardPolicy(String taskId) {
		this.taskId = taskId;
	}

	/**
	 * @description: 不做任何處理直接拋棄任務
	 */
	@Override
	public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
		//計劃執行的大致任務數
		String taskCount = String.valueOf(executor.getTaskCount());
		//正在執行任務的大致線程數
		String activeCount = String.valueOf(executor.getActiveCount());
		//不處理使用拋棄策略
		logger.error("RejectedDiscardPolicy.rejectedExecution, taskId :{}, task count: {}, active thread: {}", taskId,
				taskCount, activeCount);
	}

}

/**
 * @description: 自定義飽和策略(拋棄舊任務策略)
 */
class RejectedDiscardOldestPolicy implements RejectedExecutionHandler {
	protected Logger logger = LoggerFactory.getLogger(this.getClass());
	/**
	 * 執行任務的標識
	 */
	private String taskId;

	public String getTaskId() {
		return taskId;
	}

	public void setTaskId(String taskId) {
		this.taskId = taskId;
	}

	public RejectedDiscardOldestPolicy(String taskId) {
		this.taskId = taskId;
	}

	/**
	 * @description: 先將阻塞隊列中的當前任務拋棄,再嘗試提交任務。如果此時阻塞隊列使用PriorityBlockingQueue優先級隊列,將會導致優先級最高的任務被拋棄,因此不建議將該種策略配合優先級隊列使用。
	 */
	@Override
	public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
		if (!executor.isShutdown()) {
			executor.getQueue().poll();
			executor.execute(r);
		}
		logger.error("RejectedDiscardOldestPolicy.rejectedExecution,taskId:{}", taskId);
	}

}


/**
 * @description: 自定義飽和策略(調用者運行)
 */
class RejectedCallerRunsPolicy implements RejectedExecutionHandler {
	protected Logger logger = LoggerFactory.getLogger(this.getClass());
	/**
	 * 執行任務的標識
	 */
	private String taskId;

	public String getTaskId() {
		return taskId;
	}

	public void setTaskId(String taskId) {
		this.taskId = taskId;
	}

	public RejectedCallerRunsPolicy(String taskId) {
		this.taskId = taskId;
	}

	/**
	 * @description: 既不拋棄任務也不拋出異常,直接運行任務的run方法,換言之將任務回退給調用者來直接運行。
	 * 使用該策略時線程池飽和後將由調用線程池的主線程自己來執行任務,
	 * 因此在執行任務的這段時間裏主線程無法再提交新任務,從而使線程池中工作線程有時間將正在處理的任務處理完成。
	 */
	@Override
	public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
		if (!executor.isShutdown()) {
			r.run();
		}
		logger.warn("RejectedCallerRunsPolicy.rejectedExecution,taskId:{}", taskId);
	}

}

代碼參考博文

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章