**java設定一段程式碼執行超時時間(轉)**
引用網址:https://blog.csdn.net/a9529lty/article/details/42711029
前段時間在搞一個批量處理程式,涉及到多執行緒操作。但是後臺服務很不給力,併發一大常常就掛了,長時間不給返回,導致我的程式也掛死在那裡……
那麼能不能設定一段程式碼執行的超時時間呢?如果處理超時就忽略該錯誤繼續向下執行。
可是在網上搜了大半天,找到的都是無用的程式碼,根本不能用。
查了大量資料後發現,java早已經給我們提供瞭解決方案。jdk1.5自帶的併發庫中Future類就能滿足這個需求。Future類中重要方法包括get()和cancel()。get()獲取資料物件,如果資料沒有載入,就會阻塞直到取到資料,而 cancel()是取消資料載入。另外一個get(timeout)操作,表示如果在timeout時間內沒有取到就失敗返回,而不再阻塞。
到這裡,此問題就迎刃而解了。廢話不多說,直接上程式碼:
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import com.sun.corba.se.impl.orbutil.closure.Future;
import com.sun.corba.se.impl.orbutil.threadpool.TimeoutException;
public class ThreadTest {
public static void main(String[] args) throws InterruptedException,
ExecutionException {
final ExecutorService exec = Executors.newFixedThreadPool(1);
Callable<String> call = new Callable<String>() {
public String call() throws Exception {
//開始執行耗時操作
Thread.sleep(1000 * 5);
return "執行緒執行完成.";
}
};
try {
Future<String> future = exec.submit(call);
String obj = future.get(1000 * 1, TimeUnit.MILLISECONDS); //任務處理超時時間設為 1 秒
System.out.println("任務成功返回:" + obj);
} catch (TimeoutException ex) {
System.out.println("處理超時啦....");
ex.printStackTrace();
} catch (Exception e) {
System.out.println("處理失敗.");
e.printStackTrace();
}
// 關閉執行緒池
exec.shutdown();
}
}
注意,以上程式碼需要 1.5 以上的 jdk 才可編譯。
執行後可以發現丟擲了 TimeoutException ,列印出了"處理超時啦…" 的文字,在此處可進行超時後的處理。
=end=華麗的分割線================
如果對執行緒、執行緒池不太瞭解,向下繼續
引用:https://www.cnblogs.com/Steven0805/p/6393443.html
Java執行緒池ExecutorService
開篇前,我們先來看看不使用執行緒池的情況:
new Thread的弊端
執行一個非同步任務你還只是如下new Thread嗎?
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
}
}).start();
那你就太out了,new Thread的弊端如下:
a. 每次new Thread新建物件效能差。
b. 執行緒缺乏統一管理,可能無限制新建執行緒,相互之間競爭,及可能佔用過多系統資源導致當機或oom。
c. 缺乏更多功能,如定時執行、定期執行、執行緒中斷。
相比new Thread,Java提供的四種執行緒池的好處在於:
a. 重用存在的執行緒,減少物件建立、消亡的開銷,效能佳。
b. 可有效控制最大併發執行緒數,提高系統資源的使用率,同時避免過多資源競爭,避免堵塞。
c. 提供定時執行、定期執行、單執行緒、併發數控制等功能。
一 Java通過Executors提供四種執行緒池,分別為:
newCachedThreadPool建立一個可快取執行緒池,如果執行緒池長度超過處理需要,可靈活回收空閒執行緒,若無可回收,則新建執行緒。
newFixedThreadPool 建立一個定長執行緒池,可控制執行緒最大併發數,超出的執行緒會在佇列中等待。
newScheduledThreadPool 建立一個定長執行緒池,支援定時及週期性任務執行。
newSingleThreadExecutor 建立一個單執行緒化的執行緒池,它只會用唯一的工作執行緒來執行任務,保證所有任務按照指定順序(FIFO, LIFO, 優先順序)執行。
二、 ExecutorService 的submit() 與execute()區別
1、接收的引數不一樣 submit()可以接受runnable和callable 有返回值
execute()接受runnable 無返回值
2、submit有返回值,而execute沒有
Method submit extends base method Executor.execute by creating and returning a Future that can be used to cancel execution and/or wait for completion.
用到返回值的例子,比如說我有很多個做validation的task,我希望所有的task執行完,然後每個task告訴我它的執行結果,是成功還是失敗,如果是失敗,原因是什麼。
3、submit方便Exception處理
There is a difference when looking at exception handling. If your tasks throws an exception and if it was submitted with execute this exception will Go to the uncaught exception handler (when you don’t have provided one explicitly, the default one will just print the stack trace to System.err). If you submitted the task with submit any thrown exception, checked or not, is then part of the task’s return status. For a task that was submitted with submit and that terminates with an exception, the Future.get will rethrow this exception, wrapped in an ExecutionException.
意思就是如果你在你的task裡會丟擲checked或者unchecked exception,而你又希望外面的呼叫者能夠感知這些exception並做出及時的處理,那麼就需要用到submit,通過捕獲Future.get丟擲的異常。
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class ExecutorServiceTest {
public static void main(String[] args) {
ExecutorService executorService = Executors.newCachedThreadPool();
List<Future<String>> resultList = new ArrayList<Future<String>>();
// 建立10個任務並執行
for (int i = 0; i < 10; i++) {
// 使用ExecutorService執行Callable型別的任務,並將結果儲存在future變數中
Future<String> future = executorService.submit(new TaskWithResult(i));
// 將任務執行結果儲存到List中
resultList.add(future);
}
executorService.shutdown();
// 遍歷任務的結果
for (Future<String> fs : resultList) {
try {
System.out.println(fs.get()); // 列印各個執行緒(任務)執行的結果
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
executorService.shutdownNow();
e.printStackTrace();
return;
}
}
}
}
class TaskWithResult implements Callable<String> {
private int id;
public TaskWithResult(int id) {
this.id = id;
}
/**
* 任務的具體過程,一旦任務傳給ExecutorService的submit方法,則該方法自動在一個執行緒上執行。
*
* @return
* @throws Exception
*/
public String call() throws Exception {
System.out.println("call()方法被自動呼叫,幹活!!! " + Thread.currentThread().getName());
if (new Random().nextBoolean())
throw new TaskException("Meet error in task." + Thread.currentThread().getName());
// 一個模擬耗時的操作
for (int i = 999999999; i > 0; i--)
;
return "call()方法被自動呼叫,任務的結果是:" + id + " " + Thread.currentThread().getName();
}
}
class TaskException extends Exception {
public TaskException(String message) {
super(message);
}
}
執行的結果類似於:
call()方法被自動呼叫,幹活!!! pool-1-thread-1
call()方法被自動呼叫,幹活!!! pool-1-thread-2
call()方法被自動呼叫,幹活!!! pool-1-thread-3
call()方法被自動呼叫,幹活!!! pool-1-thread-5
call()方法被自動呼叫,幹活!!! pool-1-thread-7
call()方法被自動呼叫,幹活!!! pool-1-thread-4
call()方法被自動呼叫,幹活!!! pool-1-thread-6
call()方法被自動呼叫,幹活!!! pool-1-thread-7
call()方法被自動呼叫,幹活!!! pool-1-thread-5
call()方法被自動呼叫,幹活!!! pool-1-thread-8
call()方法被自動呼叫,任務的結果是:0 pool-1-thread-1
call()方法被自動呼叫,任務的結果是:1 pool-1-thread-2
java.util.concurrent.ExecutionException: com.cicc.pts.TaskException: Meet error in task.pool-1-thread-3
at java.util.concurrent.FutureTask$Sync.innerGet(FutureTask.java:222)
at java.util.concurrent.FutureTask.get(FutureTask.java:83)
at com.cicc.pts.ExecutorServiceTest.main(ExecutorServiceTest.java:29)
Caused by: com.cicc.pts.TaskException: Meet error in task.pool-1-thread-3
at com.cicc.pts.TaskWithResult.call(ExecutorServiceTest.java:57)
at com.cicc.pts.TaskWithResult.call(ExecutorServiceTest.java:1)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
at java.util.concurrent.FutureTask.run(FutureTask.java:138)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:619)
可以看見一旦某個task出錯,其它的task就停止執行。
三、shotdown() showdownNow()區別
可以關閉 ExecutorService,這將導致其拒絕新任務。提供兩個方法來關閉 ExecutorService。
shutdown() 方法在終止前允許執行以前提交的任務,
shutdownNow() 方法阻止等待任務啟動並試圖停止當前正在執行的任務。在終止時執行程式沒有任務在執行,也沒有任務在等待執行,並且無法提交新任務。關閉未使用的 ExecutorService 以允許回收其資源。
一般分兩個階段關閉 ExecutorService。第一階段呼叫 shutdown 拒絕傳入任務,然後呼叫 shutdownNow(如有必要)取消所有遺留的任務
// 啟動一次順序關閉,執行以前提交的任務,但不接受新任務。
threadPool.shutdown();
四、Runnable()與Callable()區別
如果是一個多執行緒協作程式,比如菲波拉切數列,1,1,2,3,5,8…使用多執行緒來計算。
但後者需要前者的結果,就需要用callable介面了。
callable用法和runnable一樣,只不過呼叫的是call方法,該方法有一個泛型返回值型別,你可以任意指定。
runnable介面實現的沒有返回值的併發程式設計。
callable實現的存在返回值的併發程式設計。(call的返回值String受泛型的影響) 使用Future獲取返回值。
(1). newCachedThreadPool
建立一個可快取執行緒池,如果執行緒池長度超過處理需要,可靈活回收空閒執行緒,若無可回收,則新建執行緒。示例程式碼如下:
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
final int index = i;
try {
Thread.sleep(index * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
cachedThreadPool.execute(new Runnable() {
@Override
public void run() {
System.out.println(index);
}
});
}
執行緒池為無限大,當執行第二個任務時第一個任務已經完成,會複用執行第一個任務的執行緒,而不用每次新建執行緒。
(2). newFixedThreadPool
建立一個定長執行緒池,可控制執行緒最大併發數,超出的執行緒會在佇列中等待。示例程式碼如下:
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
for (int i = 0; i < 10; i++) {
final int index = i;
fixedThreadPool.execute(new Runnable() {
@Override
public void run() {
try {
System.out.println(index);
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}
因為執行緒池大小為3,每個任務輸出index後sleep 2秒,所以每兩秒列印3個數字。
定長執行緒池的大小最好根據系統資源進行設定。如Runtime.getRuntime().availableProcessors()。可參考PreloadDataCache。
(3) newScheduledThreadPool
建立一個定長執行緒池,支援定時及週期性任務執行。延遲執行示例程式碼如下:
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
scheduledThreadPool.schedule(new Runnable() {
@Override
public void run() {
System.out.println("delay 3 seconds");
}
}, 3, TimeUnit.SECONDS);
表示延遲3秒執行。
定期執行示例程式碼如下:
scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
System.out.println("delay 1 seconds, and excute every 3 seconds");
}
}, 1, 3, TimeUnit.SECONDS);
表示延遲1秒後每3秒執行一次。
ScheduledExecutorService比Timer更安全,功能更強大,後面會有一篇單獨進行對比。
(4)、newSingleThreadExecutor
建立一個單執行緒化的執行緒池,它只會用唯一的工作執行緒來執行任務,保證所有任務按照指定順序(FIFO, LIFO, 優先順序)執行。示例程式碼如下:
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
for (int i = 0; i < 10; i++) {
final int index = i;
singleThreadExecutor.execute(new Runnable() {
@Override
public void run() {
try {
System.out.println(index);
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}
結果依次輸出,相當於順序執行各個任務。
現行大多數GUI程式都是單執行緒的。Android中單執行緒可用於資料庫操作,檔案操作,應用批量安裝,應用批量刪除等不適合併發但可能IO阻塞性及影響UI執行緒響應的操作。
總結:
(1)使用ExecutorService的submit函式由於execute函式
(2)異常如何處理,異常後其他task停止
相關文章
- python之為函式執行設定超時時間(允許函式執行的最大時間)Python函式
- 記一次.net core 非同步執行緒設定超時時間非同步執行緒
- Spring Boot中得定時任務執行一段時間後突然停了Spring Boot
- CSocket設定超時(轉)
- mysql sql語句執行超時設定MySql
- 如何測量程式碼執行時間
- 如何在Python退出時強制執行一段程式碼Python
- PAT-B 1026 程式執行時間【時間】
- FFmpeg轉碼音影片時間戳設定分析時間戳
- Java專案計算程式執行時間方法Java
- sleep 時間段不佔指令碼執行時間指令碼
- Linux 檢視程式啟動時間、執行時間Linux
- Linux 中如何設定每個特定的時間執行特定的程式Linux
- JavaScript 計算程式碼執行花費時間JavaScript
- Java程式碼實現帶時區時間字串轉為LocalDateTime物件Java字串LDA物件
- unity C# 每隔一段時間執行一次UnityC#
- PAT乙級1026程式執行時間(秒數轉換為時間)(值得學習)
- linux系統時間程式設計(9) 計算程式片段執行時間clock函式Linux程式設計函式
- Stopwatch 計算程式執行時間
- 1026. 程式執行時間(15)
- Linux 定時執行指令碼、命令Linux指令碼
- Linux定時執行.sh指令碼Linux指令碼
- Java執行緒的CPU時間片Java執行緒
- Java如何測量方法執行時間Java
- 關於MySql 設定一個間隔時間 執行一個事件MySql事件
- MongoDB 超時設定MongoDB
- SSH 超時設定
- dubbo 超時設定和原始碼分析原始碼
- python程式計算執行時間差Python
- 通過 Redis 定時執行指令碼Redis指令碼
- 【Python】Python 使用http時間同步設定系統時間原始碼PythonHTTP原始碼
- MySQL定時執行MySql
- 設定mysql 事務鎖超時時間 innodb_lock_wait_timeoutMySqlAI
- Linux時間設定系統時間、硬體時間和時間服務Linux
- 最近有好長一段時間沒有敲程式碼了...
- Java之時間轉換Java
- java時間格式轉化Java
- JAVA將一段時間 按周、月、季度、半年、年進行分割Java