精华内容
下载资源
问答
  • 线程池异步调用 SpringBoot框架自动装配提供了一个线程池,用于提交异步任务 有了线程池我们就只需要写任务即可,提交任务采用**@Async**注解 例如: 打印结果: 该线程池可根据需要进行配置 或者在配置文件中...

    线程池异步调用

    SpringBoot框架自动装配提供了一个线程池,用于提交异步任务
    有了线程池我们就只需要写任务即可,提交任务采用**@Async**注解
    例如:
    在这里插入图片描述
    在这里插入图片描述
    打印结果:
    在这里插入图片描述
    该线程池可根据需要进行配置
    在这里插入图片描述
    在这里插入图片描述
    或者在配置文件中进行配置
    在这里插入图片描述

    展开全文
  • 第一步: 需要在启动类加入@EnableAsync使异步调用@Async注解生效, 在需要异步执行的方法上加入此注解即可@Async("threadPool"),threadPool为自定义线程池 在默认情况下,未设置TaskExecutor时,默认是使用...

    应用场景:

    发送短信,日志记录,等与主线程无关的业务。

    第一步:

    需要在启动类加入@EnableAsync使异步调用@Async注解生效,

    在需要异步执行的方法上加入此注解即可@Async("threadPool"),threadPool为自定义线程池

    在默认情况下,未设置TaskExecutor时,默认是使用SimpleAsyncTaskExecutor这个线程池,但此线程不是真正意义上的线程池,因为线程不重用,每次调用都会创建一个新的线程。可通过控制台日志输出可以看出,每次输出线程名都是递增的。所以最好我们来自定义一个线程池。

    什么情况下会导致@Async异步方法会失效?

    1. 调用同一个类下注有@Async异步方法:在spring中像@Async和@Transactional、cache等注解本质使用的是动态代理,其实Spring容器在初始化的时候Spring容器会将含有AOP注解的类对象“替换”为代理对象(简单这么理解),那么注解失效的原因就很明显了,就是因为调用方法的是对象本身而不是代理对象,因为没有经过Spring容器,那么解决方法也会沿着这个思路来解决。
    2. 调用的是静态(static )方法
    3. 调用(private)私有化方法

    第二步:自己来个demo

    package com.thread.pool.task.thread_pool.config;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.scheduling.annotation.EnableAsync;
    import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
    
    import java.util.concurrent.ThreadPoolExecutor;
    
    @Configuration
    @EnableAsync
    public class ThreadPoolTaskConfig {
    
    
        /**
         * 如下方式会完全使@Async 失效
         * 1,异步方法使用static修饰
         * 2.异步类没有使用Component注解(或其他注解导致spring无法扫描到异步类
         * 3.异步方法不能与异步方法在同一类在同一个类
         * 4.在本类中调用本类得异步方法无效 在spring中像@Async和@Transactional、cache等注解本质使用的是动态代理,其实Spring容器在初始化的时候Spring容器会将含有AOP注解的类对象“替换”为代理对象(简单这么理解),那么注解失效的原因就很明显了,就是因为调用方法的是对象本身而不是代理对象,因为没有经过Spring容器,那么解决方法也会沿着这个思路来解决。
         * 5.如果使用springboot框架必须在启动类中增加@EnableAsnc注解
         * @return
         */
    
        @Bean("threadPoolTaskExecutor")
        public ThreadPoolTaskExecutor threadPoolTaskExecutor(){
    
            ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
            threadPoolTaskExecutor.setCorePoolSize(1);
            threadPoolTaskExecutor.setMaxPoolSize(4);
            threadPoolTaskExecutor.setQueueCapacity(4);
            threadPoolTaskExecutor.setKeepAliveSeconds(30);
            threadPoolTaskExecutor.setThreadNamePrefix("异步调用线程名称前缀:");
            threadPoolTaskExecutor.setWaitForTasksToCompleteOnShutdown(true);
            threadPoolTaskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
            threadPoolTaskExecutor.initialize();
            return threadPoolTaskExecutor;
        }
    
    
    
    }
    

     

    package com.thread.pool.task.thread_pool.service;
    
    public interface HelloService {
    
    
        void hello(int i);
    }
    
    package com.thread.pool.task.thread_pool.service.impl;
    
    import com.thread.pool.task.thread_pool.service.HelloService;
    import org.springframework.scheduling.annotation.Async;
    import org.springframework.stereotype.Service;
    
    @Service
    public class HelloServiceImpl  implements HelloService {
        @Override
        @Async("threadPoolTaskExecutor")
        public void hello(int i) {
            System.out.println("异步调用第:"+ i+" 次");
        }
    }
    
    package com.thread.pool.task.thread_pool.controller;
    
    import com.thread.pool.task.thread_pool.service.HelloService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.ResponseBody;
    
    @Controller
    public class HelloWorldController {
    
        @Autowired
        private HelloService helloService;
    
        @GetMapping(value = "/hello")
        @ResponseBody
        public String  hello(){
            for (int i = 0; i < 10; i++) {
                helloService.hello(i);
            }
            return "hello";
    
        }
    
    }
    

    查看控制台输出是无序说明异步调用:

    我们把@Async 先注释掉再进行请求查看:结果是按照顺序输出

    • 异步请求和异步调用的使用到这里基本就差不多了,有问题还希望大家多多指出。
    • 如果感觉不明显还有另一种方式,就是把循环中输出的i追加到一个字符串中进行返回,如果hello()方法上没有加@Async注解那么返回的字符串一定是0-9,如果加上了@Async注解返回的字符串就是比较随机,拼接返回的字符串就是在主线程执行完之前异步调用执行的结果的拼接结果。

     

     

     

     

     

     

     

    展开全文
  • @GetMapping("/test") public String getExamineReportList() { //异步调用的方法 ttest.get(); log.info("主线程:"+Thread.currentThread().getName()); return "我还活着"; } } //异步方法 @Slf4j @Component ...

     配置线程池

    @EnableAsync
    @Configuration
    public class ThreadPoolConfig {
    
        @Bean("queryThreadPool")
        public ThreadPoolTaskExecutor queryThreadPool(){
            ThreadPoolTaskExecutor tengxuThreadPool = new ThreadPoolTaskExecutor();
            tengxuThreadPool.setCorePoolSize(5);
            tengxuThreadPool.setMaxPoolSize(10);
            tengxuThreadPool.setQueueCapacity(25);
            //配置线程池前缀
            tengxuThreadPool.setThreadNamePrefix("query-");
            tengxuThreadPool.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
            tengxuThreadPool.initialize();
            return tengxuThreadPool;
        }
    }

     来一个controller

    @Slf4j
    @RestController
    public class Test {
    
        @Autowired
        private Ttest ttest;
    
        @GetMapping("/test")
        public String getExamineReportList() {
            //异步调用的方法
            ttest.get();
            log.info("主线程:"+Thread.currentThread().getName());
            return "我还活着";
        }
    }
    //异步方法
    @Slf4j
    @Component
    public class Ttest {
    
        @Async("queryThreadPool")
        public void get(){
            log.info("异步:"+Thread.currentThread().getName());
            try {
                Thread.sleep(30000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            log.info("异步线程end:"+Thread.currentThread().getName());
        }
    }

    注意事项

    不要写在同一类里面

    不能在同一类下调用@Async注解的方法,例如A类下有a和b方法,b方法上有@Async注解,不能直接a调用b,要把b放到其他类中才可以。

    展开全文
  • 可以直接使用JAVA线程池技术,new一个线程调用B系统的接口,达到异步调用的目的。  这样的话,A系统就只管发送数据了,无需理会B系统接口的处理速度如何,也不会被B系统的接口阻塞住。但是此时还是有两个问题:  1、...

    生产者-消费者模式在系统交互方面,有几个特点: 
    1、系统解耦 
    2、解决并发问题 
    3、不需要关心对方系统何时处理数据,处理结果如何

    下面用几个简单例子逐步说明。


    简单例子


    假设有两个系统,A系统和B系统,B系统需要依赖A系统产生的数据,也就是说,A系统产生数据后,必须把数据扔给B系统。 
    这个时候,可以让B系统提供一个方法,比如说提供一个http接口sendData(),然后A系统直接调用即可。

    这里写图片描述

    这种方案在流量不大的情况下,完全没问题的,但是如果系统并发量大的情况下,每次A系统同步调用B系统的sendData()接口时,就会被阻塞住,如果sendData方法处理的很慢,那么会直接影响A系统的吞吐量的。 
    因此最好能异步的调用B系统的接口,然后A系统可以立刻返回,继续处理其他事情。

    可以直接使用JAVA的线程池技术,new一个线程调用B系统的接口,达到异步调用的目的。 
    这里写图片描述

    这样的话,A系统就只管发送数据了,无需理会B系统接口的处理速度如何,也不会被B系统的接口阻塞住。但是此时还是有两个问题: 
    1、B系统此时需要做一些应付大并发量的处理,因为面对A系统的狂轰滥炸,B系统可能处理不过来的。 
    2、A系统和B系统还是耦合了。因为A系统还是直接调用B系统接口,直接交互的。

    有没有更好的方案,双方既能处理并发,同时两个系统之间又无需耦合呢?答案是使用生产者-消费者模式


    生产者-消费者模式


    生产者-消费者模式通过引入一个阻塞队列这个第三方组件来做到解耦和处理并发。 
    生产者只需要往队列里面塞数据,消费者只需要从队列中读取数据,生产者再也无需关注消费者处理数据的速度是如何了。生产者和消费者已经是完全独立的了。 
    利用某些队列特性,当生产者速度太快的话,数据超过了队列的最大阀值,那么可以自动阻塞住生产者(当然也可以设置线程阻塞的超时时间,防止消费者挂掉了,一直不处理队列中的数据,生产者),一直等到消费者先消费一些数据。

    这里写图片描述


    进一步思考


    之前写过一篇ThreadPoolExecutor简单介绍介绍了JAVA线程池的一些基本用法,ThreadPoolExecutor也利用了生产者-消费者模式的思想,只不过 
    ThreadPoolExecutor是有必要的时候才使用队列,性能是比上面的直接使用队列的方式性能要高很多的。实际操作中也可以借鉴这种做法。

    转载于:https://www.cnblogs.com/maohuidong/p/8034203.html

    展开全文
  • 线程池异步调用获取主线程上下文

    千次阅读 2020-05-09 16:45:26
    在实际开发中遇到的问题,用线程池另起一个线程执行代码时,存在主线程里的上下文信息就会丢失,我这报出的错误是获取不到用户的登陆信息,所以找了些资料和同事讨论,得出了以下解决方案,将上下文信息传入新的线程,具体...
  • @Async public void executeAsyncTask(Object obj) { *** }
  • java异步线程,java异步调用线程池中的线程,Java实现异步调用二、Futurejdk8之前的实现方式,在JUC下增加了Future,从字面意思理解就是未来的意思,但使用起来却着实有点鸡肋,并不能实现真正意义上的异步,获取结果...
  • 目录 一、SpringBoot异步线程池 1、定义线程池 2、线程池的使用 ...三、Java线程池 1、使用线程池的优势 2、什么是阻塞队列? 3、线程池为什么要是使用阻塞队列? 4、如何配置线程池? ...
  • @Async()注解可以写上线程池名称,这样就会指定使用的线程池,当然我们需要自定义线程池,这边我写上不同的线程池名称,等下可以看结果; /** * fshows.com * Copyright (C) 2013-2019 All Rights Rese...
  • java线程池-异步

    2019-11-26 15:17:53
    在java中,如果需要设定代码执行的最长时间,即超时,可以用Java线程池ExecutorService类配合Future接口来实现。 Future接口是Java标准API的一部分,在java.util.concurrent包中。Future接口是Java线程Future模式的...
  • java实现异步调用

    万次阅读 2020-07-21 17:21:02
    1、使用线程池的逻辑实现异步调用 package com.ourlang.dataextract.controller; import com.google.common.util.concurrent.ThreadFactoryBuilder; import com.ourlang.dataextract.common.CommonResult; import ...
  • 线程池同步、异步调用Callable,Future 涉及内容 案例分析,用Future获取线程池执行结果 原理分析:Future实现原理 使用Future来获取线程池执行 代码 package com.myd.cn.ThreadLocal; import java.util....
  • 线程池异步回调方式

    2020-10-10 15:40:28
    文章目录线程池异步回调方式代码展示首先需要封装一个Task类创建一个业务层去调用这个任务并且放入线程池中控制层去调用调用截图总结 线程池异步回调方式 ​ 当请求进入Controller层中的时候,我们要经历一系列的...
  • Java 实现异步调用

    万次阅读 热门讨论 2018-04-03 15:27:12
    首先 我遇到的问题是 接口调用时需要更新缓存 而更新缓存又是个说快不快的过程 所以打算做异步调用 返回我所需要的结果即可 ,至于缓存什么时候更新完 就不是我所需要关注的了废话不多说 上代码public class ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 68,367
精华内容 27,346
关键字:

java线程池异步调用

java 订阅