這是蘑菇街一面面試官問我的一個問題。他說:如果有這麼一個場景,我執行業務的時候,不想讓業務執行時間超過一定時間,如果超出就停止執行,你怎麼來設計!
我們在學習Java並行程式設計的時候,那些常見的方法大多都有設定超時時間的引數,我們可以根據這一思路來設計超時結束任務的方案。我這裡用到的是Thread.join()方法,先來解釋下join方法吧。
join()方法:如果一個執行緒A執行了thread.join()語句,其含義是:當前執行緒A等待thread執行緒終止之後才從thread.join()返回。執行緒Thread除了提供join()方法之外,還提供了join(long millis)和join(long millis,int nanos)兩個具備超時特性的方法。這兩個超時方法表示,如果執行緒thread在給定的超時時間裡沒有終止,那麼將會從該超時方法中返回。摘自《Java並行程式設計的藝術》
我們來看下join的原始碼:
public final synchronized void join(long millis)
throws InterruptedException {
long base = System.currentTimeMillis();
long now = 0;
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (millis == 0) {
while (isAlive()) {
wait(0);
}
} else {
//正常來說,我們會進入到這裡,進入到迴圈裡,直到呼叫join方法的執行緒執行完畢之後或者超出時間限制了,才退出。
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
}
}
其實我感覺書中對join的解釋還是有那麼一點欠缺的,我認為是:當在主執行緒A中呼叫另一個執行緒B的join方法意味著,從一開始的A、B兩個執行緒並行執行變為序列執行的了,也就是將B執行緒插入到A執行緒中,然後等待B執行緒執行完成以後,再執行剩下的A執行緒的任務了。如果這個join方法帶有超時引數的話,可以理解為,在這段時間內,A等待B執行緒執行(序列),一旦超出這個時間,兩個執行緒又會回到並行執行的狀態了。
回到我們之前的問題 ,我們想設計一個超時退出的介面,就可以利用這個帶有超時引數的join來實現,來看看我的程式碼,注意看註釋。
package com.markus.basic.Java多執行緒.方法超時問題;
/**
* Author:markusZhang
* Date:Create in 2020/10/8 12:57
* todo:
*/
public class JoinDemo {
public static void main(String[] args){
Thread method = new Thread(new ThreadMethod());
//呼叫方法
method.start();
try {
method.join(2000);//規定業務介面執行不能超過的時長
} catch (InterruptedException e) {
e.printStackTrace();
}
method.interrupt();//呼叫中斷很重要,如果不呼叫的話,就會回到上面說的,兩個執行緒並行執行,就起不到效果了。
}
}
class ThreadMethod implements Runnable{
@Override
public void run() {
try {
Thread.sleep(3000);//執行業務
System.out.println("方法呼叫完成");
} catch (InterruptedException e) {
//e.printStackTrace();
System.out.println("方法呼叫超時");
}
}
}
當然了,設計任務執行超時退出有很多種方案,這個只是其中一種。在開發中,我們需要多注意下那些帶有超時引數的方法,說不定也是可以設計的。