精华内容
下载资源
问答
  • 多线程Spring注入失败

    2018-05-15 08:22:24
    在对Spring进行测试(多线程环境)时发现ExpertBlogService一直注入失败,后来发现多线程环境下Spring是不会对新线程进行管理的,所以需要我们手动加载配置文件,另外将加载部分部分放进静态块中防止多次加载,代码...

        在对Spring进行测试(多线程环境)时发现ExpertBlogService一直注入失败,后来发现多线程环境下Spring是不会对新线程进行管理的,所以需要我们手动加载配置文件,另外将加载部分部分放进静态块中防止多次加载,代码如下:

        private static ApplicationContext ctx = null;

        private static ExpertBlogService expertBlogService;

        private static ExpertBlogMapper expertBlogMapper;

        //When you use @Autowired in a new thread,you will get a nullpointerException
        static {
            ctx = new ClassPathXmlApplicationContext("classpath:spring/applicationContext.xml");
            expertBlogMapper = (ExpertBlogMapper) ctx.getBean("expertBlogMapper");
            expertBlogService = new ExpertBlogServiceImpl(expertBlogMapper);
        }
    展开全文
  • 多线程Spring注入对象问题的四种解法 前言 当我们使用多线程时,想给线程注入一个service,但是运行时发现service总是为null。举个????: public class MyThread implements Runnable { @Autowired Service ...

    多线程Spring注入对象问题的四种解法

    前言

    当我们使用多线程时,想给线程注入一个service,但是运行时发现service总是为null。
    举个🌰:

    public class MyThread implements Runnable {
    
        @Autowired
        Service application;
    
        public void run() {}
    }
    

    原因

    new Thread不在spring容器中,也就无法获得spring中的bean对象。根据SpringBean的生命周期,能够被Spring管理的Bean都是在扫描范围内并且有 @Componen、@Service、@Configuration 等注释,在使用时才能用IOC注入对象。如果使用new 关键字手动生成的对象,Sring感知不到,无法管理。

    解决办法

    主要有四种,分为两种思路:

    • 继续使用new 关键字
      • 依赖通过构造函数传入
      • 依赖通过 ApplicationContext 手动获取
      • 使用 @Configurable 注解 管理线程内部的依赖
    • 不使用new 关键字
      • 配合 @Scope("prototype") 使用SpringBean的方式创建线程

    一 最简单的方法 – 通过构造器传入依赖

    public class TaskComments implements Callable<List<String>> {
    
        private RedisClient redisClient;
        private TaskComments(RedisClient redisClient){
            this.redisClient = redisClient;
        }
        
        @Override
        public List<String> call() throws Exception {
            //业务代码
        }
    }
    

    二 在线程内部使用手动获取的方式

    1. 配置类
    @Component
    public class BeanContext implements ApplicationContextAware {
    
        private static ApplicationContext applicationContext;
    
        @Override
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            BeanContext.applicationContext = applicationContext;
        }
    
        public static <T> T getBean(Class<T> clz) throws BeansException {
            return (T) applicationContext.getBean(clz);
        }
    }
    
    1. 使用
    public class TaskComments implements Runable<List<String>> {
    
        private RedisClient redisClient = BeanContext.getBean(RedisClient.class);
        
        @Override
        public void run() throws Exception {
            //业务代码
        }
    }
    

    三 使用@Configurable

    注释的官方解释:
    不是基于Spring的应用程序中使用的所有类型(bean)都是Spring管理的。有时,我们需要将一些依赖注入到一些非Spring管理的类型中。最常见的例子是在实体类中注入服务或DAO层。现在实体类的实例使用 new 创建,也即它们不是被Spring管理的。现在我们想要在这个类型中注入对应的Service或DAO类型,被注入类型是被Spring管理的,以上这些操作可以在 @Configurable 的帮助下完成。

    @Configurable
    public class TaskComments implements Runnable{
    	@Autowired
        private Service service;
        	
        @Override
        public void run() throws Exception {
            //业务代码
        }
    }
    

    四 使用@Scope(“prototype”)

    这个注释的意思是在注入Bean时不采用Spring默认的单例模式,每次新创建一个对象。由于在创建线程时,通常是用线程池提交Runable任务,两个都是使用new 关键词创建的,因此两个都得改造。但是线程池对象只需要一个,所以采用传统的单例模式即可。

    1. 自己的configuration 类 新增一个bean(也可以使用xml 的方式实现,只要是Spring管理的就好)
    @Bean
    public ThreadPoolTaskExecutor taskExecutor() {
        return new ThreadPoolTaskExecutor();
    }
    
    1. 使用@Scope(“prototype”)修饰线程任务
    @Component
    @Scope("prototype")
    public class MyThread implements Runnable { 
    	@Autowired
        private Service service;
        	
        @Override
        public void run() throws Exception {
            //业务代码
        }
    }
    
    1. 使用
    @Component
    public class MyServiceCreationListener implements ApplicationListener<ContextRefreshedEvent> {
    
        @Autowired
        private ApplicationContext ctx;
        @Autowired
        private TaskExecutor taskExecutor;        
    
        @Override
        public void onApplicationEvent(ContextRefreshedEvent event) {
    
            if (event.getApplicationContext().getParent() == null) {
                System.out.println("\nThread Started");
                //注意这里线程池和线程都没有使用 new 关键字新建
                taskExecutor.execute(ctx.getBean(MyThread.class));
            }
        }
    }
    

    参考

    Stack Overflow
    Stack Overflow
    博客

    展开全文
  • 在用多线程的时候,里面要用到Spring注入服务层,或者是逻辑层的时候,一般是注入不进去的。具体原因应该是线程启动时没有用到Spring实例不池。所以注入的变量值都为null。 如果在run方法里面加载application.xml,...

    在用多线程的时候,里面要用到Spring注入服务层,或者是逻辑层的时候,一般是注入不进去的。具体原因应该是线程启动时没有用到Spring实例不池。所以注入的变量值都为null。

    如果在run方法里面加载application.xml,来取得bean时,由于重复加载,一般情况下会耗尽内存,抛出内存溢出错误。所以这的确是一个很头痛的问题。

    有一个方法可以解决注不进去的问题。就是在声明变量的时候,前面加static。这样在初始化的时候它就会加载application.xml,得到bean。

    关于这个问题的根本机制没有作深入的研究,好在问题解决了。

    从这个例子体会到林信良说过的,没有一个技术是完美的,不要为了Spring而Spring。不要为了注入而注入。

    展开全文
  • Spring Async多线程使用

    2020-06-08 17:47:42
    本文记录Spring Async对Java多线程的支持 使用场景 Java在处理多线程时需要用到线程池及其相关的API,配置较为零散,学习成本较高.Spring提供了便捷的配置类来支持多线程的实现. 技术点 Java多线程 Spring Async ...

    本文记录Spring Async对Java多线程的支持


    使用场景

    Java在处理多线程时需要用到线程池及其相关的API,配置较为零散,学习成本较高.Spring提供了便捷的配置类来支持多线程的实现.

    技术点

    • Java多线程
    • Spring Async

    Spring Async配置类

    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.Executor;
    import java.util.concurrent.ThreadPoolExecutor;
    
    /**
     * 开启多线程操作,注解方式
     * 在需要进行异步处理的方法上加上@Async注解
     */
    @Configuration
    @EnableAsync
    public class AsyncConfig {
    
        /**
         * 设置线程池基本大小值, 线程池维护线程的最少数量
         */
        private int corePoolSize = 10;
        /**
         * 设置线程池最大值
         */
        private int maxPoolSize = 200;
        /**
         * 线程池所使用的缓冲队列大小
         */
        private int queueCapacity = 1024;
        /**
         * 配置线程最大空闲时间
         */
        private int keepAliveSeconds = 50000;
    
        @Bean
        public Executor asyncExecutor() {
            ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
            executor.setCorePoolSize(corePoolSize);
            executor.setMaxPoolSize(maxPoolSize);
            executor.setQueueCapacity(queueCapacity);
            executor.setKeepAliveSeconds(keepAliveSeconds);
            executor.setThreadNamePrefix("AsyncExecutor-");
    
            /*
             * rejection-policy:当pool已经达到max size的时候,如何处理新任务
             * CALLER_RUNS:不在新线程中执行任务,而是由调用者所在的线程来执行
             */
            executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
            executor.initialize();
            return executor;
        }
    }
    
    
    

    Spring Async服务类-控制层

    import org.eureka.service.impl.AsyncService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.RestController;
    
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.Future;
    
    /**
     * Description: 异步任务测试类
     */
    @RestController
    public class AsyncController {
        @Autowired
        private AsyncService asyncService;
     
        @RequestMapping(value = "/hello",method = RequestMethod.GET)
        public String testAsyncNoRetrun(){
            long start = System.currentTimeMillis();
             asyncService.doNoReturn();
             return String.format("任务执行成功,耗时{%s}", System.currentTimeMillis() - start);
        }
    
        @GetMapping("/hi")
        public Map<String, Object> testAsyncReturn() throws ExecutionException, InterruptedException {
            long start = System.currentTimeMillis();
    
            Map<String, Object> map = new HashMap<>();
            List<Future<String>> futures = new ArrayList<>();
            for (int i = 0; i < 10; i++) {
                Future<String> future = asyncService.doReturn(i);
                futures.add(future);
            }
            /*
             * 读取的时候,记得要批量读取不能单独读取,否则无法实现异步的效果
             * 且需要注意:
             * 异步方法调用一定需要通过Spring代理,@Async和@Transactional注解类似,只有在代理模式下生效
             */
            List<String> response = new ArrayList<>();
            for (Future future : futures) {
                String string = (String) future.get();
                response.add(string);
            }
            map.put("data", response);
            map.put("消耗时间", String.format("任务执行成功,耗时{%s}毫秒", System.currentTimeMillis() - start));
            return map;
        }
    }
    
    
    

    Spring Async服务类-实现层

    import org.springframework.scheduling.annotation.Async;
    import org.springframework.scheduling.annotation.AsyncResult;
    import org.springframework.stereotype.Service;
    
    import java.util.Date;
    import java.util.concurrent.Future;
    
    /**
     * Description: 异步任务测试类
     */
    @Service
    public class AsyncService {
    
        /**
         * TODO 处理无返回的异步任务
         * @param
         * @return void
         * @throws
         * @date 2019/8/20 16:34
         **/
        @Async
        public void doNoReturn(){
            try {
                // 这个方法执行需要三秒
                Thread.sleep(3000);
                System.out.println("方法执行结束" + new Date());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
        /**
         * TODO 处理有返回的异步任务
         * @param i
         * @return java.util.concurrent.Future<java.lang.String>
         * @throws
         * @date 2019/8/20 16:35
         **/
        @Async
        public Future<String> doReturn(int i){
            try {
                // 这个方法需要调用500毫秒
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // 消息汇总
            return new AsyncResult<>(String.format("这个是第{%s}个异步调用的证书", i));
        }
    }
    
    
    
    展开全文
  • java多线程spring多线程实现

    千次阅读 2018-04-02 16:37:18
    java多线程spring多线程实现 线程thread 线程的创建方法: 1、继承Thread类创建新的可执行线程 class PrimeThread extends Thread { long minPrime; PrimeThread(long minPrime) { this.minPrime = ...
  • 因为最近项目上线,需要同步期初数据-工序,大概有120万数据,采用之前Mybatis批量插入,一次5000的方式,单线程,大概...Spring是通过任务执行器(TaskExecutor)来实现多线程和并发编程,使用ThreadPoolTaskExecutor
  • Spring通过任务执行器(TaskExecutor)来实现多线程和并发编程。使用ThredPoolTaskExecutor可以实现基于线程池的TaskExecutor。 为了实现异步任务,可以在配置类中通过 @Enable开启对异步任务的支持,并通过实际执行...
  • Spring 多线程

    千次阅读 2017-03-17 13:43:10
    Spring 通过任务执行器(TaskExecutor)来实现多线程和并发编程。使用ThreadPoolTaskExecutor可以实现一个基于线程池的TaskExecutor。而实际上开发中的任务一般是非阻塞的,即异步的,所以我们要在配置类中通过@...
  •  Spring通过任务执行器(TaskExecutor)来实现多线程和并发编程。使用ThreadPoolTaskExecutor可实现一个基于线程池的TaskExecutor。而实际开发中任务一般是非阻碍的,即异步的,所以我们要在配置类中通过@...
  • Spring Boot 多线程

    2021-04-29 16:28:30
    在我们的系统中,经常会处理一些耗时任务,自然而然的会想到使用多线程,JDK给我们提供了非常方便的操作线程的API,为什么还要使用Spring来实现多线程呢? 1.使用Spring比使用JDK原生的并发API更简单。(一个注解@...
  • spring多线程 spring自带的多线程ThreadPoolTaskExecutor,用的就是java的ThreadPoolExecutor,接下来就来对比一下他们的使用和对比一下java多线程spring多线程 配置类 @Configuration @ComponentScan("...
  • Spring多线程

    2017-09-20 16:55:00
    Spring是通过TaskExecutor任务执行器来实现多线程和并发编程的。使用ThreadPoolTaskExecutor可实现一个基于线程池的TaskExecutor。而实际开发中任务一般是非阻碍的,即异步的,所以我们要在配置类中通过@EnableAsync...
  • Spring Boot多线程demo

    2018-12-16 10:24:03
    springboot多线程范例,Spring Boot中使用多线程的方式有很多种,最简单的方式就是使用@Async注解来实现。
  • Spring Boot2.x 使用多线程

    千次阅读 2019-04-29 17:00:05
    关于Spring Boot多线程 Spring是通过任务执行器(TaskExecutor)来实现多线程和并发编程,使用ThreadPoolTaskExecutor来创建一个基于线城池的TaskExecutor。在使用线程池的大多数情况下都是异步非阻塞的。我们配置注解...
  • spring 多线程

    2018-02-24 15:54:38
    package ... import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler; import org.springframework.context.annotation.ComponentScan; import org....
  • spring异步多线程

    2019-08-04 20:45:23
    spring异步多线程配置对异步任务的支持异步任务类测试类 配置对异步任务的支持 spring通过任务执行器TaskExecutor来实现多线程和并发编程。 使用ThreadPoolTaskExecutor可以实现一个基于线程池的TaskExecutor ...
  • spring 多线程事务

    2019-09-12 07:38:49
    由于 项目开发,有第三方的回调。...可能需要用到 多线程,所以 测试了一下 spring多线程事务。 1, 在 controller 新建一个线程执行 service的 事务情况 new Thread(new Runnable() { @Override public ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 8,698
精华内容 3,479
关键字:

多线程spring

spring 订阅