面試官:請你設計一個任務執行超時退出的介面!

2020-10-09 11:00:24

文章目錄

前言

這是蘑菇街一面面試官問我的一個問題。他說:如果有這麼一個場景,我執行業務的時候,不想讓業務執行時間超過一定時間,如果超出就停止執行,你怎麼來設計!

思路

我們在學習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("方法呼叫超時");
        }
    }
}

總結

當然了,設計任務執行超時退出有很多種方案,這個只是其中一種。在開發中,我們需要多注意下那些帶有超時引數的方法,說不定也是可以設計的。