1. 程式人生 > >執行緒中斷機制,精確控制方法執行

執行緒中斷機制,精確控制方法執行

在Java中,有沒有一種方式,可以使正在執行的方法,終止執行呢?

比如說:一個方法,我只想讓它執行10分鐘,超過十分鐘,就馬上停止執行。執行了多少,未執行多少,就記錄下它的執行狀態即可。

今天,我就跟大家分享一個方案。

在這裡:

1、使用JDK中提供的Callable和Future幫助實現;

2、使用Spring託管管理執行緒池;

3、控制方法執行10分鐘,10分鐘內執行完,正常返回;10分鐘之外,報錯超時,執行中斷操作。

先看一段虛擬碼:

package com.creditease.monitor;

import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

@Service
public class CheckService {
	
	/** 執行緒池 */
	@Autowired
	private ThreadPoolTaskExecutor taskExecutor;
	
	private final Logger logger = LoggerFactory.getLogger(CheckService.class);
	
	public void check(){
		
		CheckTask checkTask = new CheckTask();
		Future<String> futureTask = taskExecutor.submit(checkTask);
		
		try {
			futureTask.get(10, TimeUnit.MINUTES);
		} catch (InterruptedException e) {  
			//中斷時的處理
			logger.error("執行了中斷處理", e);
		} catch (ExecutionException e) {
			//方法報錯
			logger.error("方法報錯",e);
		} catch (TimeoutException e) {
			//超時
			logger.error("方法超時",e);
		}finally {
			
			//方法執行完時,設定中斷
			futureTask.cancel(true);
		}
	}

	class CheckTask implements Callable<String>{

		@Override
		public String call() throws Exception {
			
			String strReturn = null;
			List<String> list = Arrays.asList("one","two","three","four","five","six","seven","eight");
			Iterator<String> iterator = list.iterator();
			
			//如果執行緒處於中斷狀態,則立即返回
			//TODO:do something more than 10mins
			while (iterator.hasNext() && !Thread.currentThread().isInterrupted()) {
				
				//TODO:do someting to get the result 'strReturn' 
				
				break;
			}
			return strReturn;
		}
	}
}


相應的執行緒池配置:

<bean id="taskExecutor"
	class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
		<!-- 核心執行緒數 -->
		<property name="corePoolSize" value="10" />
		<!-- 最大執行緒數 -->
		<property name="maxPoolSize" value="30" />
		<!-- 佇列最大長度 >=mainExecutor.maxSize 預設為 Integer.MAX_VALUE-->
		<property name="queueCapacity" value="1000" />
		
		<!-- 執行緒池維護執行緒所允許的空閒時間 -->
		<property name="keepAliveSeconds" value="300" />
		<!-- 執行緒池對拒絕任務(無執行緒可用)的處理策略 -->
		<property name="rejectedExecutionHandler">
			<bean class="java.util.concurrent.ThreadPoolExecutor$CallerRunsPolicy" />
		</property>
	</bean>

分析一下:

在這段程式中,具體執行邏輯在CheckTask類中,執行緒池taskExecutor提交任務後,進入等待狀態。

futureTask.get(10,TimeUnit.NINUTES)執行,獲取執行結果時,主執行緒進入等待狀態,具體執行邏輯的執行緒被喚醒執行邏輯。

如果執行邏輯10分鐘內,成功獲取到結果,那麼方法正常返回;

如果方法執行,超過10分鐘,則主執行緒被強制喚醒,並返回超時結果,即執行TimeoutException部分。

與此通知,注意與此同時:這時執行finally塊兒中的futureTask.cancel(true)方法。這是主執行緒向執行邏輯執行緒傳送中斷訊號。

注意:這時,在具體執行邏輯中,Thread.currentThread().isInterrupted()方法將變為true。也就是說,這是具體執行邏輯類的方法,也將終止執行並返回。

其實,這裡就是我想跟大家分享的關鍵點:執行緒中斷。

這裡如果沒有在finally塊兒中,執行futureTask.cancel(true),也就是這樣:

//方法執行完時,設定中斷
			//futureTask.cancel(true);

這樣,執行結果將會如何呢?

很簡單,如果超過十分鐘,具體邏輯執行緒還未執行完的話,那麼主執行緒依然會超時返回;而具體邏輯執行緒,則會將未執行完的任務執行完。也許是15分鐘,也許是半個小時。也就是說,future.get()方法,能夠保證一定時間內返回,但是Java中並沒有給出一個執行緒kill掉另一個執行緒的方法。

注意:方法超時時,futureTask.get()並不能獲取正常的結果返回了,這是Java中斷機制所限制的,具體結果,可以通過其他方案彌補解決。

但是,Java提供了一種中斷機制,需要開發人員輔助,來完成這個控制操作。

注意:如果在CheckTask類中,while邏輯迴圈中,存在 Thread.sleep()方法,以及wait()方法,那麼我們就可以不使用中斷機制了,也能達到執行緒中斷的目的。原因就是,Java的執行緒中斷機制中,執行執行緒收到中斷訊號,如果執行緒未處於啟用狀態,就會執行緒就會被中斷。