zoukankan      html  css  js  c++  java
  • 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
    信息: 所有任务执行完毕
    
    
  • 相关阅读:
    深入理解linux启动过程
    Oracle 12c 的新功能:模式匹配查询
    AIX 常用命令汇总
    Oracle 11g ADRCI工具使用
    AIX TL的升级和回退
    oracle redo log的维护
    202. Happy Number
    198. House Robber
    203. Remove Linked List Elements
    217. Contains Duplicate
  • 原文地址:https://www.cnblogs.com/zhazhaacmer/p/11362316.html
Copyright © 2011-2022 走看看