Asynchronous task processing using thread pool

Create a thread pool

Ali JAVA coding specification, it is recommended to use ThreadPoolExecutor to create a thread pool.

    private static ExecutorService simpleExecutorService = new ThreadPoolExecutor(
            200,
            300,
            0L,
            TimeUnit.MICROSECONDS,
            new LinkedBlockingDeque<Runnable>(10000),
            new ThreadPoolExecutor.DiscardPolicy());

Asynchronous operations are completed through a thread pool during a synchronous operation

public void doSomething(final String message) {
        simpleExecutorService.execute(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(3000);
                    System.out.println("step 2");
                    System.out.println("message=>" + message);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        System.out.println("step 1");
    }

carry out testing

ThreadUtil threadUtil = new ThreadUtil();
threadUtil.doSomething("a thread pool demo");

output result

step 1
step 2
message=>a thread pool demo

@Async

After Spring 3.x, the framework has supported the use of @Async annotation for asynchronous execution.

The methods modified by @Async are called asynchronous methods. These asynchronous methods are processed in a new thread and do not affect the sequential execution of the main thread.

Execute without return value

@Component
@Slf4j
public class AsyncTask {

    @Async
    public void dealNoReturnTask(){
        log.info("Thread {} deal No Return Task start", Thread.currentThread().getName());
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.info("Thread {} deal No Return Task end at {}", Thread.currentThread().getName(), System.currentTimeMillis());
    }
}

Make a call:

@SpringBootTest(classes = SpringbootApplication.class)
@RunWith(SpringJUnit4ClassRunner.class)
@Slf4j
public class AsyncTest {

    @Autowired
    private AsyncTask asyncTask;

    @Test
    public void testDealNoReturnTask(){
        asyncTask.dealNoReturnTask();
        try {
            log.info("begin to deal other Task!");
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

Execute with return value

    @Async
    public Future<String> dealHaveReturnTask() {
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("thread", Thread.currentThread().getName());
        jsonObject.put("time", System.currentTimeMillis());
        return new AsyncResult<String>(jsonObject.toJSONString());
    }

Determine whether the task is canceled:

    @Test
    public void testDealHaveReturnTask() throws Exception {

        Future<String> future = asyncTask.dealHaveReturnTask();
        log.info("begin to deal other Task!");
        while (true) {
            if(future.isCancelled()){
                log.info("deal async task is Cancelled");
                break;
            }
            if (future.isDone() ) {
                log.info("deal async task is Done");
                log.info("return result is " + future.get());
                break;
            }
            log.info("wait async task to end ...");
            Thread.sleep(1000);
        }
    }

Asynchronous execution result exception handling

We can implement the AsyncConfigurer interface, or inherit the AsyncConfigurerSupport class to realize that when creating a thread pool in the method getAsyncExecutor(), we must use executor.initialize(), otherwise the thread pool uninitialized exception will be reported when calling. If the bean is defined using threadPoolTaskExecutor(), no initialization is required

@Configuration
@EnableAsync
@Slf4j
public class AsyncConfig implements AsyncConfigurer {

//    @Bean
//    public ThreadPoolTaskExecutor threadPoolTaskExecutor(){
//        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//        executor.setCorePoolSize(10);
//        executor.setMaxPoolSize(100);
//        executor.setQueueCapacity(100);
//        return executor;
//    }

    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(10);
        executor.setMaxPoolSize(100);
        executor.setQueueCapacity(100);
        executor.setThreadNamePrefix("AsyncExecutorThread-");
        executor.initialize(); //如果不初始化,导致找到不到执行器
        return executor;
    }
    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return new AsyncExceptionHandler();
    }
}

Asynchronous exception handling class:

@Slf4j
public class AsyncExceptionHandler implements AsyncUncaughtExceptionHandler {
    @Override
    public void handleUncaughtException(Throwable ex, Method method, Object... params) {
        log.info("Async method: {} has uncaught exception,params:{}", method.getName(), JSON.toJSONString(params));

        if (ex instanceof AsyncException) {
            AsyncException asyncException = (AsyncException) ex;
            log.info("asyncException:{}",asyncException.getErrorMessage());
        }

        log.info("Exception :");
        ex.printStackTrace();
    }
}

@Data
@AllArgsConstructor
public class AsyncException extends Exception {
    private int code;
    private String errorMessage;
}
  • In an asynchronous call with no return value, the asynchronous processing throws an exception, the handleUncaughtException() of AsyncExceptionHandler will catch the specified exception, and the original task will continue to run until it ends.
  • In an asynchronous call with a return value, if the asynchronous processing throws an exception, the exception will be thrown directly, the asynchronous task ends, and the original processing ends.

Future或FutureTask

Need to combine Callable

public class CallableDemo implements Callable<Integer> {

    private int sum;

    @Override
    public Integer call() throws Exception {
        System.out.println("Callable子线程开始计算啦!");
        Thread.sleep(2000);

        for(int i=0 ;i<5000;i++){
            sum=sum+i;
        }
        System.out.println("Callable子线程计算结束!");
        return sum;
    }
}

Future pattern

        //创建线程池
        ExecutorService es = Executors.newSingleThreadExecutor();
        //创建Callable对象任务
        CallableDemo calTask = new CallableDemo();

        //提交任务并获取执行结果
        Future<Integer> future = es.submit(calTask);

        //关闭线程池
        es.shutdown();

        try {
            System.out.println("主线程在执行其他任务");

            if (future.get() != null) {
                //输出获取到的结果
                System.out.println("future.get()-->" + future.get());
            } else {
                //输出获取到的结果
                System.out.println("future.get()未获取到结果");
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("主线程在执行完成");

FutureTask pattern

        //创建线程池
        ExecutorService es = Executors.newSingleThreadExecutor();
        //创建Callable对象任务
        CallableDemo calTask = new CallableDemo();

        //创建FutureTask
        FutureTask<Integer> future = new FutureTask<>(calTask);
        // future.run();  // 由于FutureTask继承于Runable,所以也可以直接调用run方法执行
        //执行任务
        es.submit(future); // 效果同上面直接调用run方法

        //关闭线程池
        es.shutdown();

        try {
            System.out.println("主线程在执行其他任务");

            if (future.get() != null) {
                //输出获取到的结果
                System.out.println("future.get()-->" + future.get());
            } else {
                //输出获取到的结果
                System.out.println("future.get()未获取到结果");
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("主线程在执行完成");

Merge asynchronous execution results

public class FutureDemo{
 
     public static void main(String[] args)  {
         Long start = System.currentTimeMillis();
         //开启多线程
         ExecutorService exs = Executors.newFixedThreadPool(10);
         try {
             //结果集
             List<Integer> list = new ArrayList<Integer>();
             List<Future<Integer>> futureList = new ArrayList<Future<Integer>>();
             //1.高速提交10个任务,每个任务返回一个Future入list
             for(int i=0;i<10;i++){
                 futureList.add(exs.submit(new CallableTask(i+1)));
             }

             Long getResultStart = System.currentTimeMillis();
             System.out.println("结果归集开始时间="+new Date());
             //2.结果归集,遍历futureList,高速轮询(模拟实现了并发)获取future状态成功完成后获取结果,退出当前循环
             for (Future<Integer> future : futureList) {
                  //CPU高速轮询:每个future都并发轮循,判断完成状态然后获取结果,这一行,是本实现方案的精髓所在。即有10个future在高速轮询,完成一个future的获取结果,就关闭一个轮询
                 while (true) {
                    //获取future成功完成状态,如果想要限制每个任务的超时时间,取消本行的状态判断+future.get(1000*1, TimeUnit.MILLISECONDS)+catch超时异常使用即可。 
                    if (future.isDone()&& !future.isCancelled()) {
                         Integer i = future.get();//获取结果
                         System.out.println("任务i="+i+"获取完成!"+new Date());
                         list.add(i);
                         break;//当前future获取结果完毕,跳出while
                     } else {
                          //每次轮询休息1毫秒(CPU纳秒级),避免CPU高速轮循耗空CPU---》新手别忘记这个
                         Thread.sleep(1);
                     }
                 }
             }

             System.out.println("list="+list);

             System.out.println("总耗时="+(System.currentTimeMillis()-start)+",取结果归集耗时="+(System.currentTimeMillis()-getResultStart));
            
         } catch (Exception e) {
             e.printStackTrace();
         } finally {
             exs.shutdown();
         }
     }
     static class CallableTask implements Callable<Integer>{
         Integer i;
         
         public CallableTask(Integer i) {
             super();
             this.i=i;
         }
 
         @Override
         public Integer call() throws Exception {
             if(i==1){
                 Thread.sleep(3000);//任务1耗时3秒
             }else if(i==5){
                 Thread.sleep(5000);//任务5耗时5秒
             }else{
                 Thread.sleep(1000);//其它任务耗时1秒
             }
             System.out.println("task线程:"+Thread.currentThread().getName()+"任务i="+i+",完成!");  
             return i;
         }
     }
 }

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325323980&siteId=291194637