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.主题

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
信息: 所有任务执行完毕

posted @ 2019-08-16 10:26  山枫叶纷飞  阅读(1366)  评论(0编辑  收藏  举报