Java併發和多執行緒3:執行緒排程和有條件取消排程

小雷FansUnion發表於2015-12-31


在第1篇中“併發框架基本示例”,提到了Executors和ThreadPool。
其中,還有個“定時排程”的方法,Executors.newScheduledThreadPool(10)。
// 可執行排程命令(定時+週期性)的執行緒池,擁有固定的執行緒數
	// 重複執行,無窮盡
	public static void scheduledThreadPool() {
		int initialDelay = 10;
		int period = 10;
		Executor executor = Executors.newScheduledThreadPool(10);
		ScheduledExecutorService scheduler = (ScheduledExecutorService) executor;
		scheduler.scheduleAtFixedRate(task, initialDelay, period,
				TimeUnit.SECONDS);
	}


這段程式碼,會一直重複執行,是一種常見的場景。

但是,想到一種“只排程N次”的需求,看了下API,沒有提供。
就網上搜尋“Java 取消執行緒排程”,找到了1個問答,就研究了下。
程式碼示例的關鍵是,使用了執行緒安全的AtomicInteger和通用同步工具CountDownLatch。

核心邏輯就是,當超過了最大任務數N的時候,取消Future中的任務,countDownLatch中的計數器-1,變為0,“countDownLatch.await()”執行緒阻塞結束
countDownLatch.countDown();
關於CountDownLatch的進一步介紹,請參考第4篇。

package cn.fansunion.executorframework;


import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;


//有條件地,取消排程
public class ConditionCancelSchedulerDemo {


	public static Runnable task = new Runnable() {
		@Override
		public void run() {
			System.out.println("Execute a task");
		}
	};


	// 可執行排程命令(定時+週期性)的執行緒池,擁有固定的執行緒數
	// 重複執行,無窮盡
	public static void scheduledThreadPool() {
		int initialDelay = 10;
		int period = 10;
		Executor executor = Executors.newScheduledThreadPool(10);
		ScheduledExecutorService scheduler = (ScheduledExecutorService) executor;
		scheduler.scheduleAtFixedRate(task, initialDelay, period,
				TimeUnit.SECONDS);
	}


	public static void main(String[] args) throws Exception {
		scheduledThreadPool();
		conditionCancelScheduler();
	}


	private static void conditionCancelScheduler() throws InterruptedException {
		final String jobID = "my_job_1";
		final AtomicInteger count = new AtomicInteger(0);
		final Map<String, Future> futures = new HashMap<>();
		// 最多執行10個任務
		final int maxTaskSize = 10;
		// CountDownLatch的更多用法,請參考CountDownLatchDemo
		final CountDownLatch countDownLatch = new CountDownLatch(1);
		ScheduledExecutorService scheduler = Executors
				.newSingleThreadScheduledExecutor();


		Future future = scheduler.scheduleWithFixedDelay(new Runnable() {
			@Override
			public void run() {
				System.out.println(count.getAndIncrement());
				// 當排程執行,第maxTaskSize+1個任務的時候,取消Future中的任務。第11個任務
				if (count.get() > maxTaskSize) {
					System.out.println("a");
					Future f = futures.get(jobID);
					if (f != null) {
						f.cancel(true);
					}
					// countDownLatch中的計數器-1,變為0
					// “countDownLatch.await()”執行緒阻塞結束
					countDownLatch.countDown();
				}
			}
		}, 0, 1, TimeUnit.SECONDS);


		futures.put(jobID, future);
		countDownLatch.await();


		scheduler.shutdown();
	}
}




更多程式碼示例:
http://git.oschina.net/fansunion/Concurrent(逐步更新中)


參考資料:
java併發程式設計-Executor框架
http://www.iteye.com/topic/366591


有條件地終止 ScheduledExecutorService 中執行的定時任務
http://www.oschina.net/question/1158769_119659?sort=time


JDK API 文件

相關文章