1. 程式人生 > >java多執行緒實現任務超時監聽

java多執行緒實現任務超時監聽

在實際的開發過程當中,會遇到這樣的需求:某些功能為了防止系統掛死,需要進行時間控制,超過一定的執行時間,就提示任務執行超時,不再繼續執行該任務,從而保證系統健壯性和穩定性。其實仔細想想,我們可以把這樣的需求,全部歸結為一種“超時控制的業務模型”,建立起自己熟悉的業務模型,以後碰到類似的需求,可以借鑑此方案。若有機會設計或重構系統,在必要的模組中,也可以將該方案作為增強系統穩定性的一個備選方案。

方案一:使用守護執行緒

此方案需要的類有:

TimeoutThread:定義超時的執行緒,裡面包含超時時間和是否執行完成狀態定義。主要任務就是監聽時間,超出時間後丟擲執行時異常。

TimeoutException:定義的一個執行時異常,繼承RuntimeException。如果覺得名字有重複的話,也可以換成別的名字。

TaskThread:定義任務執行的執行緒,守護執行緒,包含成員變數TimeoutThread,裡面主要執行任務主體,任務執行完後,修改TimeoutThread的狀態為執行完成。

MyUncauhtExceptionHandler:自定義的執行緒異常捕獲類,在守護程序由於超時被迫銷燬時,能夠執行這個異常裡的程式碼,一般用於任務執行主體超時後的狀態改變,如將任務標記為超時狀態。各位請注意:執行緒中丟擲的異常,是不能夠被直接捕獲的。

MyHandlerThreadFactory(可選):實現ThreadFactory介面,執行緒的建立工廠,在這裡主要是為執行緒池修改預設為執行緒異常捕獲工廠,若在程式碼中設定Thread.setDefaultUncaughtExceptionHandler(new MyUncauhtExceptionHandler());,則該類可以不用,但一般寫法需要用到該類。建議使用該類

Client:用於演示效果的類。

示例程式碼如下:

public class TimeoutThread implements Runnable {

	private long timeout;
	private boolean isCancel;
	
	public TimeoutThread(long timeout) {
		super();
		this.timeout = timeout;
	}

	/**
	 * 設定監聽是否取消
	 */
	public void isCancel() {
		this.isCancel = true;
	}
	
	@Override
	public void run() {
		try {
			Thread.sleep(timeout);
			if(!isCancel) {
				throw new TimeoutException("thread is timeout");
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

}
public class TimeoutException extends RuntimeException {

	private static final long serialVersionUID = 551822143131900511L;

	
	/**
	 * 丟擲異常資訊
	 * @param str 異常資訊
	 */
	public TimeoutException(String str) {
		super(str);
	}
	
}
public class TaskThread extends Thread{

	private TimeoutThread tt;
	
	/**
	 * 需要注入TimeoutThread物件
	 * 可根據不同的場景,注入不同的物件,完成任務的執行
	 * @param tt
	 */
	public TaskThread(TimeoutThread tt) {
		this.setDaemon(true);
		this.tt = tt;
	}
	
	@Override
	public void run() {
		try {
			//這裡是任務的執行主體,為了簡單示例,只用sleep方法演示
			Thread.sleep(1000);
			//執行任務完成後,更改狀態
			tt.isCancel();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
	}

}
public class MyUncauhtExceptionHandler implements Thread.UncaughtExceptionHandler {

	@Override
	public void uncaughtException(Thread t, Throwable e) {
		//簡單起見,只打印一句話
		System.out.println("hehe");
	}

}
public class MyHandlerFactory implements ThreadFactory {

	@Override
	public Thread newThread(Runnable r) {
		//定義執行緒建立工廠,這裡主要設定MyUncauhtExceptionHandler
		Thread t = new Thread(r);
		t.setUncaughtExceptionHandler(new MyUncauhtExceptionHandler());
		return t;
	}

}
public class Client {

	public static void main(String[] args) {
		//方式一:直接設定DefaultUncaughtExceptionHandler,然後直接t.start();task.start()啟動執行緒即可。
		Thread.setDefaultUncaughtExceptionHandler(new MyUncauhtExceptionHandler());
		//方式二:建立執行緒建立工廠,利用執行緒池啟動執行緒
		ExecutorService exec = Executors.newCachedThreadPool(new MyHandlerFactory());
		TimeoutThread tt = new TimeoutThread(800);
		Thread t = new Thread(tt);
		TaskThread task = new TaskThread(tt);
		exec.execute(t);
		exec.execute(task);
		exec.shutdown();
	}
}

方案二:使用Future的特性(推薦)

利用Future.get(long timeout,   TimeUnit unit)方法。

1、新建TaskThread類,實現Callable介面,實現call()方法。

2、執行緒池呼叫submit()方法,得到Future物件。

3、呼叫Future物件的get(long timeout,   TimeUnit unit)方法,該方法的特點:阻塞式執行緒呼叫,同時指定了超時時間timeout,get方法執行超時會丟擲timeout異常,該異常需要捕獲。

示例程式碼:

public class TimeTask implements Callable<String> {

	@Override
	public String call() throws Exception {
		//執行任務主體,簡單示例
		Thread.sleep(1000);
		return "hehe";
	}

}
                ExecutorService exec = Executors.newCachedThreadPool();
		Future<String> f = exec.submit(new TimeTask());
		try {
			f.get(200, TimeUnit.MILLISECONDS);
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (ExecutionException e) {
			e.printStackTrace();
		} catch (TimeoutException e) {
			//定義超時後的狀態修改
			System.out.println("thread time out");
			e.printStackTrace();
		}


方案總結:

       花了比較多的篇幅介紹方案一,主要目的是瞭解java 執行緒的基本處理方案機制,守護執行緒的特性,執行緒異常的處理方法。可以通過這個方案,多瞭解一些java的基礎知識。個人建議不推薦在企業應用開發中使用此方案。

       方案二利用現有的Future屬性,在開發過程中直接利用JDK的方法,省時省力,並且可靠性高。

相關推薦

java執行實現任務超時

在實際的開發過程當中,會遇到這樣的需求:某些功能為了防止系統掛死,需要進行時間控制,超過一定的執行時間,就提示任務執行超時,不再繼續執行該任務,從而保證系統健壯性和穩定性。其實仔細想想,我們可以把這樣的需求,全部歸結為一種“超時控制的業務模型”,建立起自己熟悉的業務模型,以

使用Java執行實現任務分發

多執行緒下載由來已久,如 FlashGet、NetAnts 等工具,它們都是依懶於 HTTP 協議的支援(Range 欄位指定請求內容範圍),首先能讀取出請求內容 (即欲下載的檔案) 的大小,劃分出若干區塊,把區塊分段分發給每個執行緒去下載,執行緒從本段起始處下載資料及至

java 執行實現任務分發

      1:需要被執行的任務列表,2:啟動的執行緒數.存在問題:怎樣知道哪個執行緒執行哪些任務總共包含三個類 1:taskdistributor  任務分發器,2:待執行的任務,3:工作執行緒。Taskdistributor.javaimport java.util.A

Java執行實現電影院售票案例

某電影院目前正在上映賀歲大片,共有100張票,而它有3個售票視窗,請設計一個程式模擬該電影院售票。 定義Sell類實現Runnable介面,很好的解決了單繼承共享資源問題 public class Sell implements Runnable { // 定義100張票,三個售票

Java 執行實現死鎖場景

簡述: 《Java 程式設計思想》  P718 ~ P722 模擬死鎖的場景, 三個人 三根筷子,每個人需要拿到身邊的兩根筷子才能開始吃飯 出現死鎖的場景是,三個人都拿到了右邊的筷子,但是由於筷子都被搶佔,均無法獲得左邊的筷子 Chopstick.java

java執行5.任務執行

將應用程式的工作分解到多個任務中,可以簡化程式的組織結構,提供一種自然的事務邊界來優化錯誤恢復過程,並提供一種自然的並行工作結構來提升併發性 理想情況下,能找出清晰的任務邊界,各個任務之間是相互獨立的,任務不依賴於其他任務的狀態、結果或邊界效應。 在正常的負載下,伺服器應用程式應該同時表現出良好

java:執行(實現Runnable的原理)及二種方式的區別

* 1,看Thread類的建構函式,傳遞了Runnable介面的引用  * 2,通過init()方法找到傳遞的target給成員變數的target賦值 * 3,檢視run方法,發現run方法中有判斷,如果target不為null就會呼叫Runnable介面子類物件的run方法 *

Java執行實現的方式

Java多執行緒實現的方式有四種 1.繼承Thread類,重寫run方法 2.實現Runnable介面,重寫run方法,實現Runnable介面的實現類的例項物件作為Thread建構函式的target 3.通過Callable和FutureTask建立執行緒 4.通過執行緒池建立執行

(CSDN遷移) JAVA執行實現-實現Runnable介面

實現Runnable介面  implements Runnable 重寫run()方法 @Override public void run(){//TODO} 建立執行緒物件: Thread thread1 = new Thread(new Implement

(CSDN遷移)JAVA執行實現-單執行執行池newSingleThreadExecutor

JAVA通過Executors提供了四種執行緒池,單執行緒化執行緒池(newSingleThreadExecutor)、可控最大併發數執行緒池(newFixedThreadPool)、可回收快取執行緒池(newCachedThreadPool)、支援定時與週期性任務的執行緒池(newScheduledThre

(CSDN遷移) JAVA執行實現-可控最大併發數執行池(newFixedThreadPool)

上篇文章中介紹了單執行緒化執行緒池newSingleThreadExecutor,可控最大併發數執行緒池(newFixedThreadPool)與其最大的區別是可以通知執行多個執行緒,可以簡單的將newSingleThreadExecutor理解為newFixedThreadPool(1)。例如執行一下兩個程

Java執行實現以及執行安全筆記

Java虛擬機器允許應用程式併發地執行多個執行緒。 以下為多執行緒的實現常用的2種方法 (1)繼承Thread類,重寫run()方法      Thread本質上也是實現了Runnable介面的一個例項,代表一個執行緒的例項。啟用執行緒的唯一方法就是通過Thread類的

java執行實現一個簡單的水池進出水問題

需求: 有一個水池100L,有出水口和入水口,出水口和入水口不能同時開啟,入水口每次注入5L水,出水口每次出4L水,如果池子注滿水,或者池子中沒有水就停止。 使用繼承Thread類的方式編寫出水口,使用實現Runnable方式編寫入水口,執行結果。 package po

Java執行實現加法計算

採用多執行緒的方式實現從1到N的和 1.直接順序計算 public static void Sum(int N){ long start1 = System.currentTimeMillis(); long sum = 0;

JAVA執行實現的四種方式

         昨天自己用ExecutorService建立執行緒池做穿透測試了一下,感覺挺有意思,所以又好好的看了一下執行緒的問題,在此轉載了一篇博友的文章,感覺總結的不錯,所以分享一下. Java多執行緒實現方式主要有四種: 繼承Thread類、實現Runnable

JAVA 執行實現方式

一般實現得方式有倆種: 實現Runnable介面。該介面中的方法run(),來實現建立執行緒。 繼承Thread類。 這倆種實現執行緒得方式對比而言: 一個Thread物件只能建立一個執行緒,即使它呼叫多次的.start()也會只執行一個的執行緒。建立多個執行緒就需要多個Thread

java執行實現搶紅包

在準備寫這個程式碼之前,我著實的複習和加深了對執行緒操作的使用,同步和資料共享! 說一下程式碼的思路: 首先搶紅包,人、紅包抽象為兩個物件,人(獲取到紅包)紅包(總額,數量,提供生成隨機金額方法) 其

Java執行-----實現生產者消費者模式的幾種方式

   1 生產者消費者模式概述      生產者消費者模式就是通過一個容器來解決生產者和消費者的強耦合問題。生產者和消費者彼此之間不直接通訊,而通過阻塞佇列來進行通訊,所以生產者生產完資料之後不用等待消費者處理, 直接扔給阻塞佇列,消費者不找生產者要資料,

JAVA執行實現的三種方式及內部原理

JAVA多執行緒實現方式主要有三種:繼承Thread類、實現Runnable介面、使用ExecutorService、Callable、Future實現有返回結果的多執行緒。其中前兩種方式執行緒執行完

java執行實現Runnable

class aa implements Runnable{ private String name; public aa(String name){ this.name=name; } public void run() { for(i