【线程】JAVA FetrueTask 超时处理 终止关闭任务线程正在执行的方法

发布时间:2023年12月22日

【线程】JAVA FetrueTask 超时处理 终止关闭任务线程正在执行的方法

终止中断关闭正在执行的方法

直接上代码:



import org.dromara.hutool.core.collection.ListUtil;
import org.dromara.hutool.core.thread.ThreadUtil;

import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class 任务延迟等待以及终止 {

//这里是JDK21的方法, 低版本的 可以用别的
    public static ExecutorService executor =  Executors.newVirtualThreadPerTaskExecutor();

    public static  long start = System.currentTimeMillis(); //获取执行到这行代码的系统时间

    public static List<Integer> 超时集合 = ListUtil.of(5000, 10000);
    

    /**
     * @param args
     */
    public static void main(String[] args) {

        try{
            String result = 启动任务();  //调用timeoutMethod(timeout)方法,并传一个实参
            System.out.println("整个方法实际耗时:" + (System.currentTimeMillis() - start) + "毫秒");  //打印执行完timeoutMethod(timeout)的方法时间
            System.out.println("结果:" + result);
        }catch(Exception e){
            e.printStackTrace();
            System.out.println("异常");
        }
        System.out.println("60 * 1000 * 100000");
        ThreadUtil.sleep(60 * 1000 * 100000);
    }

    /**
     * 有超时时间的方法
     * @return
     */
    private  static String 启动任务()  throws Exception{
        String result = "false";

        /**
         * 一个可取消的异步计算。该类提供了一个基类
         */
        FutureTask<String> futureTask = new FutureTask<>(new Callable<String>() { 

            @Override
            public String call() throws Exception {
                //TODO
                boolean bool = 模拟阻塞执行的方法();
                return "false";
            }
        });

//        Thread futureTask = new Thread(() -> {
//            //TODO
//            try {
//                boolean bool = unknowMethod(); //调用unkonwMethod(time)方法
//            } catch (Exception e) {
//                throw new RuntimeException(e);
//            }
//        });

        //开始执行任务
        executor.execute(futureTask); //池化线程或调用中执行futureTask
        
        ThreadUtil.sleep(6000);

        for (int i = 0; i < 超时集合.size(); i++) {
            Integer time = 超时集合.get(i);

            try {
                //这个方法会阻塞,直到任务完成时会返回
                result = futureTask.get(time, TimeUnit.MILLISECONDS); 
            } catch (InterruptedException | ExecutionException | TimeoutException e) {
                /**
                 * 超时之后会进入这里  进行业务处理
                 */
                
                //e.printStackTrace();

                //TODO 这里通知用户 是否等待

                if(i == 0){
                    System.out.println("第一次 超时 用户点击继续等待");
                }

                if(i == 1){
                    System.out.println("第二次 超时 用户点击跳过");

                    /**
                     * 强行终止该任务
                     * 为false时,会等待这个任务执行完,返回true;若任务还没执行,取消任务后返回true,如任务执行完,返回false
                     */
                    futureTask.cancel(true);
                    System.out.println("任务已终止");
                    System.out.println("方法实际执行时间:" + (System.currentTimeMillis() - start) + "毫秒");
                    executor.shutdown();
                }
            }
        }
        
        return result;
    }

    
    /**
     * 这个方法的耗时
     * @return
     */
    private static boolean 模拟阻塞执行的方法 () throws  Exception{
        for (int i = 0; i < 100000000; i++) {
            System.out.println("执行中..." + i);
            Thread.sleep(1000);
        }
        System.out.println("任务需要耗时: " + 0 + "毫秒" + "___标志");
        return true;
    }

}

前言

我们先来了解下同步、异步有什么区别?
同步(Sync)

所谓同步,就是发出一个功能调用时,在没有得到结果之前,该调用就不返回或继续执行后续操作。

根据这个定义,Java中所有方法都是同步调用,应为必须要等到结果后才会继续执行。我们在说同步、异步的时候,一般而言是特指那些需要其他端协作或者需要一定时间完成的任务。

简单来说,同步就是必须一件一件事做,等前一件做完了才能做下一件事。

异步(Async)

异步与同步相对,当一个异步过程调用发出后,调用者在没有得到结果之前,就可以继续执行后续操作。当这个调用完成后,一般通过状态、通知和回调来通知调用者。对于异步调用,调用的返回并不受调用者控制。

对于通知调用者的三种方式,具体如下:

情况作用
状态即监听被调用者的状态(轮询),调用者需要每隔一定时间检查一次,效率会很低。
通知当被调用者执行完成后,发出通知告知调用者,无需消耗太多性能。
回调与通知类似,当被调用者执行完成后,会调用调用者提供的回调函数。

FutureTask概念

FutureTask一个可取消的异步计算,FutureTask 实现了Future的基本方法,可以查询计算是否已经完成,并且可以获取计算的结果。结果只可以在计算完成之后获取,get方法会阻塞当计算没有完成的时候,一旦计算已经完成,那么计算就不能再次启动或是取消。

一个FutureTask 可以用来包装一个 Callable 或是一个runnable对象。因为FurtureTask实现了Runnable方法,所以一个 FutureTask可以提交(submit)给一个Excutor执行(excution).

FutureTask使用场景

FutureTask可用于异步获取执行结果或取消执行任务的场景。通过传入Runnable或者Callable的任务给FutureTask,直接调用其run方法或者放入线程池执行,之后可以在外部通过FutureTask的get方法异步获取执行结果,因此,FutureTask非常适合用于耗时的计算,主线程可以在完成自己的任务后,再去获取结果。另外,FutureTask还可以确保即使调用了多次run方法,它都只会执行一次Runnable或者Callable任务,或者通过cancel取消FutureTask的执行等。

FutureTask执行多任务计算的使用场景

利用FutureTask和ExecutorService,可以用多线程的方式提交计算任务,主线程继续执行其他任务,当主线程需要子线程的计算结果时,在异步获取子线程的执行结果。
?

FeatureTast部分方法:

情况作用
report(int s)返回已完成任务的结果或引发异常。
isCancelled()判断task是否在正常完成前取消掉了。
isDone()返回ture或false
cancel(boolean mayInterruptIfRunning)取消task的执行,如果task已完成、已被取消、或者由于某些原因取消不了,则返回false
get()等待task完成,并获取执行结果。可能会抛出异常
get(long timeout, TimeUnit unit)在指定的时间内等待task完成,并获取执行结果。可能抛出异常(含TimeoutException)

文章来源:https://blog.csdn.net/G971005287W/article/details/135156526
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。