Java併發編程:ThreadPoolExecutor + Callable + Future(FutureTask) 探知線程的執行情況

如題 (總結要點)

  • 使用ThreadPoolExecutor來建立線程,使用Callable + Future 來執行並探知線程執行狀況;
  • V get (long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException 同上面的get功能同樣,多了設置超時時間。參數timeout指定超時時間,uint指定時間的單位,在枚舉類TimeUnit中有相關的定義。若是計算超時,將拋出TimeoutException。
  • 能夠轉換爲FutureTask: FutureTask task = (FutureTask ) poolExecutor.submit(new MyRunner(500));
  • 畢竟:class FutureTask implements RunnableFuture ,interface RunnableFuture extends Runnable, Future
  • FutureTask能夠做爲線程扔到線程池中運行,而且還能夠像下面的Future同樣探知線程的執行狀況。
  • 下面的線程池poolExecutor.submit 返回的是interface RunnableFuture extends Runnable, Future (查看源碼可知):
public <T> Future<T> submit(Runnable task, T result) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<T> ftask = newTaskFor(task, result);
        execute(ftask);
        return ftask;
    }

借鑑學習文章列表

  • 連接1:https://www.cnblogs.com/dolphin0520/p/3949310.html
  • 連接2:《java併發編程的藝術》
  • https://blog.csdn.net/yangliuhbhd/article/details/70276153

1.主題

Future接口提供方法來檢測任務是否被執行完,等待任務執行完得到結果,也能夠設置任務執行的超時時間。這個設置超時的方法就是實現Java程序執行超時的關鍵。

Future接口是一個泛型接口,嚴格的格式應該是Future<V>,其中V表明了Future執行的任務返回值的類型。 Future接口的方法介紹以下:

boolean cancel (boolean mayInterruptIfRunning) 取消任務的執行。參數指定是否當即中斷任務執行,或者等等任務結束
boolean isCancelled () 任務是否已經取消,任務正常完成前將其取消,則返回 true
boolean isDone () 任務是否已經完成。須要注意的是若是任務正常終止、異常或取消,都將返回true
V get () throws InterruptedException, ExecutionException  等待任務執行結束,而後得到V類型的結果。InterruptedException 線程被中斷異常, ExecutionException任務執行異常,若是任務被取消,還會拋出CancellationException
V get (long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException 同上面的get功能同樣,多了設置超時時間。參數timeout指定超時時間,uint指定時間的單位,在枚舉類TimeUnit中有相關的定義。若是計算超時,將拋出TimeoutException
         Future的實現類有java.util.concurrent.FutureTask<V>即 javax.swing.SwingWorker<T,V>。一般使用FutureTask來處理咱們的任務。FutureTask類同時又實現了Runnable接口,因此能夠直接提交給Executor執行。

2. 代碼

/**
 * 測試子線程,計算100之內的整數和
 */

class MyRunner implements Callable<Integer>{
    private int  sleepTime ;

    public MyRunner(int sleepTime) {
        this.sleepTime = sleepTime;
    }

    Logger logger = Logger.getLogger("myRunner");
    @Override
    public Integer call() throws Exception {
        logger.info("子線程開始運行");
        Thread.sleep(sleepTime);
        int sum = 0;
        for(int i=1;i<=100;i++){
            sum += i;
        }
        logger.info(sleepTime/1000.0+"s後,子線程結束運行.100之內的正數和爲:"+sum);
        return sum;
    }
}

3.測試 主線程啓動

import java.util.concurrent.*;
import java.util.logging.Logger;

/** https://www.cnblogs.com/dolphin0520/p/3949310.html
 * 《java併發編程的藝術》
 */
public class Test {
    private static Logger logger = Logger.getLogger("Test");
    public static void main(String[] args) {
        /**
         * 測試Callable 接口
         * 這是一個泛型接口,call()函數返回的類型就是傳遞進來的V類型
         * Callable通常是和ThreadPoolExecutor配合來使用的
         * 使用futureTask
         */
        BlockingQueue<Runnable> queue = new SynchronousQueue<>();
        ThreadFactory nameThreadFactory = new ThreadFactory() {
            @Override
            public Thread newThread(Runnable r) {
                return new Thread(r);
            }
        };
        ThreadPoolExecutor poolExecutor =
                new ThreadPoolExecutor(2, 2, 0, TimeUnit.MILLISECONDS, queue, nameThreadFactory);

        /**
         *  將實現Callable 或者runnable 接口的類提交給線程池便可
         * */
        Future<Integer> task = poolExecutor.submit(new MyRunner(500));

        poolExecutor.shutdown();

        try {
            task.get(100,TimeUnit.MILLISECONDS);
            logger.info("打印submit執行結果?是否done?");
            boolean done = task.isDone();
            logger.info(String.valueOf(done));
            // 若是沒有完成,取消當前線程的運行
            if(!done){
                task.cancel(true);
            }
        } catch (InterruptedException e) {
            task.cancel(true);
        } catch (ExecutionException e) {
            task.cancel(true);
        } catch (TimeoutException e) {
            logger.info("超時");
            task.cancel(true);
        }

        logger.info("全部任務執行完畢");
    }
}

測試結果

八月 16, 2019 10:05:18 上午 com.thread.MyRunner call
信息: 子線程開始運行
八月 16, 2019 10:05:18 上午 com.thread.Test main
信息: 超時
八月 16, 2019 10:05:18 上午 com.thread.Test main
信息: 全部任務執行完畢

測試結果2 修改 探知時間 task.get(1000,TimeUnit.MILLISECONDS);

八月 16, 2019 10:25:20 上午 com.thread.MyRunner call
信息: 子線程開始運行
八月 16, 2019 10:25:20 上午 com.thread.MyRunner call
信息: 0.5s後,子線程結束運行.100之內的正數和爲:5050
八月 16, 2019 10:25:20 上午 com.thread.Test main
信息: 打印submit執行結果?是否done?
八月 16, 2019 10:25:20 上午 com.thread.Test main
信息: true
八月 16, 2019 10:25:20 上午 com.thread.Test main
信息: 全部任務執行完畢
相關文章
相關標籤/搜索