精华内容
下载资源
问答
  • 2022-04-21 19:00:38

    背景:

    面试中会问道spring相关知识,其中有spring是否单例的问题。

    分析:

    spring 单例有时候会说的是控制层是否单例。

    从单例的概念将,就是一个例子,bean的一个实力。也就是一个类只有一个对象。有点类似单例模式的设计一样。单例模式的根本就是总体就定义全局唯一的量。在这个全局的唯一的量好去读i整个系统继续维护。

    Spring中单例的理解:

    spring在控制层层的单例呢,就是直接在控制层创建了一个单例的对象,用于对整个系统进行范围把控。目的是把系统中后续求情过来的量都进行管理。

    举例:

    启动一个项目,默认启动一个控制层的对象单例。里面存放一些必要属性。比如系统的配置属性,一般不会动,也不会改变。

    后续接到很多请求短的请求。每个请求就是一个任务,也即是一个线程(线程定义就是一个小型化的进程,就是一个小单独功能的执行任务)。这个就是多线程,线程多了之后就会涉及到线程之间数据交互的问题。

    我们知道的多线程的交互,根本上分为两种实现,1.通过每个线程内部复制一个可被访问的量 2一个是放入到本地线程中也就是ThreadLocal中的副本。

    总体都是通过复制副本拷贝,方便数据交互。

    所以这个spring 单例多线程的问题:

    即使上就是spring提供的一个先整体的环境,整体的环境下存放的被访问的数据,这个数据就是多线程中需要相互交换的数据。解决的就是一个系统过来多个任务之间的互相交互。

    更多相关内容
  • 多线程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多线程事务控制

    2021-12-03 15:40:19
    话不说直接上代码 ```/** * 将一组数据平均分成n组 * * @param source 要分组的数据源 * @param n 平均分成n组 * @param <T> * @return */ public static <T> List<List<T>> ...

    本测试多个子线程执行业务操作,我这只是简单的执行了批量添加,网上找了很多例子,杂七杂八的要么就是写的有bug要么就是运行结果不一致没效果,最后干脆自己写一个。
    话不多说直接上代码
    :

    
        @Autowired
        private PlatformTransactionManager transactionManager;
    
    ```/**
         * 将一组数据平均分成n组
         *
         * @param source 要分组的数据源
         * @param n      平均分成n组
         * @param <T>
         * @return
         */
        public static <T> List<List<T>> averageAssign(List<T> source, int n) {
            List<List<T>> result = new ArrayList<>();
            int remainder = source.size() % n;  //(先计算出余数)
            int number = source.size() / n;  //然后是商
            int offset = 0;//偏移量
            for (int i = 0; i < n; i++) {
                List<T> value = null;
                if (remainder > 0) {
                    value = source.subList(i * number + offset, (i + 1) * number + offset + 1);
                    remainder--;
                    offset++;
                } else {
                    value = source.subList(i * number + offset, (i + 1) * number + offset);
                }
                result.add(value);
            }
            return result;
        }
    // 以上是工具类
    
    
        public void test() {
            Long startTime = System.currentTimeMillis();
            DefaultTransactionDefinition def = new DefaultTransactionDefinition();
            def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
            // 获得事务状态
            TransactionStatus mainstatus = transactionManager.getTransaction(def);
            List<ZlTypeEntity> list = new ArrayList<>();
            ZlTypeEntity zlTypeEntity = null;
            for (int i = 0; i < 500000; i++) {
                zlTypeEntity = new ZlTypeEntity();
                zlTypeEntity.setName("测试" + i);
                list.add(zlTypeEntity);
            }
            //将list分成三组
            List<List<ZlTypeEntity>> listgp = ListFgUtils.averageAssign(list, 3);
           //定义子线程返回的结果集合如果全部为true则事务提交
            List<Boolean> bullist=Collections.synchronizedList(new ArrayList<>());
            //暂停当前线程
            CountDownLatch latch = new CountDownLatch(1);
            //线程计数器
            CountDownLatch cdAnswer = new CountDownLatch(2);
            for (int i = 0; i < 2; i++) {
                int finalI=i;
                ExecutorPoolUtil.fixedExecutorDiy.execute(new Runnable() {
                    @Override
                    public void run() {
                        AtomicInteger atomicInteger=new AtomicInteger();
                        atomicInteger.set(finalI+1);
                        DefaultTransactionDefinition def = new DefaultTransactionDefinition();
                        // 事物隔离级别,开启新事务
                        def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
                        // 获得事务状态
                        TransactionStatus status = transactionManager.getTransaction(def);
                        try {
                            //执行业务逻辑  子线程添加
                           AtomicBoolean a= new AtomicBoolean(saveBatch(listgp.get(atomicInteger.get())));
                           //计数
                            cdAnswer.countDown();
                           if(a.get()){
                               //添加
                               bullist.add(true);
                               //执行成功先暂停线程  等待其他线程执行结果
                               latch.await();
                               AtomicBoolean x=new AtomicBoolean(true);
                               for(int i=0;i<bullist.size();i++){
                                  if(!bullist.get(i)){
                                      x.set(bullist.get(i));
                                      break;
                                  }
                              }
                              if(x.get()){
                                  transactionManager.commit(status);
                              }
                           }else{
                               bullist.add(false);
                           }
                        } catch (Exception e) {
                            //计数
                            cdAnswer.countDown();
                            //执行异常
                            bullist.add(false);
                            status.setRollbackOnly();
                        }
                    }
                });
            }
            try{
                //等待全部线程都执行玩业务操作  (执行完后这时集合才会有全部的状态数据)
                cdAnswer.await();
                //放行 (执行全部子线程后面的代码)
                latch.countDown();
                //等待子线程执行完成(此时子线程如果状态集合都为true事务已经提交)
                latch.await();
       
                AtomicBoolean x=new AtomicBoolean(true);
              //主线程判断子线程时候有执行失败的
                for(int i=0;i<bullist.size();i++){
                    if(!bullist.get(i)){
                        x.set(bullist.get(i));
                        break;
                    }
                }
                //主线程添加
                saveBatch(listgp.get(0));
               
                if(x.get()){
          //没有则提交事务
                    transactionManager.commit(mainstatus);
                }else{
                    mainstatus.setRollbackOnly();
                }
            }catch (Exception e){
                mainstatus.setRollbackOnly();
            }
            System.out.println("耗时"+(System.currentTimeMillis()-startTime)+"ms");
        }
    
    
    
    
    展开全文
  • 主要为大家详细介绍了Spring boot多线程配置方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
  • 主要介绍了spring boot 多线程的相关资料,文中示例代码非常详细,帮助大家更好的理解和学习,感兴趣的朋友可以了解下
  • 如何使用Spring多线程

    千次阅读 2021-11-02 09:33:22
    这里写自定义目录标题为什么使用Spring多线程定义配置类在业务层使用多线程使用controller层进行测试测试结果 为什么使用Spring多线程 实际有两个原因,第一使用Spring比使用JDK原生的并发API更简单。第二我们的应用...

    为什么使用Spring多线程

    实际有两个原因,第一使用Spring比使用JDK原生的并发API更简单。第二我们的应用环境一般都会集成Spring,我们的Bean也都交给Spring来进行管理,那么使用Spring来实现多线程更加简单,更加优雅。(更多的可能是在环境中就要这么用!!)

    定义配置类

    package com.ysl.thread_demo.utils;
    
    import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.scheduling.annotation.AsyncConfigurer;
    import org.springframework.scheduling.annotation.EnableAsync;
    import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
    
    import java.util.concurrent.Executor;
    
    @Configuration
    @EnableAsync  // 启用异步任务
    public class ThreadConfig implements AsyncConfigurer {
    
        @Override
        public Executor getAsyncExecutor() {
            ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
            taskExecutor.setCorePoolSize(4);
            taskExecutor.setMaxPoolSize(20);
            taskExecutor.setQueueCapacity(30);
            taskExecutor.initialize();
            return taskExecutor;
        }
    
        @Override
        public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
            return null;
        }
    }
    
    

    在业务层使用多线程

    package com.ysl.thread_demo.service.serviceImpl;
    
    import com.ysl.thread_demo.service.TestThreadService;
    import org.springframework.scheduling.annotation.Async;
    import org.springframework.stereotype.Service;
    
    @Service
    public class TestThreadServiceImpl implements TestThreadService {
    
        @Override
        @Async	//使用@Async开启一个线程
        public void func01() throws Exception{
            for (int i = 0; i < 5; i++) {
                Thread.sleep(1000);
                System.out.println("func01运行 = " + i);
            }
        }
    
        @Override
        @Async
        public void func02() throws Exception {
            for (int i = 0; i < 5; i++) {
                Thread.sleep(1500);
                System.out.println("func02运行 = " + i);
            }
        }
    
        @Override
        @Async
        public void func03() throws Exception {
            for (int i = 0; i < 5; i++) {
                Thread.sleep(2000);
                System.out.println("func03运行 = " + i);
            }
        }
    
    }
    

    使用controller层进行测试

    package com.ysl.thread_demo.controller;
    
    import com.ysl.thread_demo.service.TestThreadService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    public class TestThreadController {
    
        @Autowired
        private TestThreadService testThreadService;
    
        @RequestMapping(value = "/testThread")
        public void testThread(){
    
            try {
                testThreadService.func01();
                testThreadService.func02();
                testThreadService.func03();
            }catch (Exception e){
                e.printStackTrace();
            }
    
        }
    
    }
    
    

    测试结果

    在这里插入图片描述

    展开全文
  • 本篇文章主要介绍了详解Spring-Boot中如何使用多线程处理任务,具有一定的参考价值,感兴趣的小伙伴们可以参考一下。
  • 主要介绍了Spring-Boot中如何使用多线程处理任务方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
  • 主要介绍了Spring boot如何通过@Scheduled实现定时任务及多线程配置,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
  • Spring Boot多线程demo

    2018-12-16 10:24:03
    springboot多线程范例,Spring Boot中使用多线程的方式有很多种,最简单的方式就是使用@Async注解来实现。
  • spring boot 纯注解方法事务控制回滚,注解+简单配置文件使用多线程demo
  • 主要介绍了Spring Boot定时任务单线程多线程实现代码解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
  • Spring多线程情况下保证事务

    千次阅读 2022-04-16 15:41:07
    Spring多线程情况下保证事务
  • 主要介绍了Spring Boot 配置和使用多线程池的实现,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
  • 主要给大家介绍了关于Spring Boot如何优雅的使用多线程的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用Spring Boot具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
  • 本篇文章主要介绍了Spring 多线程下注入bean问题详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
  • Spring多线程

    万次阅读 2018-08-10 19:50:05
    Spring通过任务执行器(TaskExecutor)来实现多线程和并发编程。 使用ThreadPoolTaskExecutor可实现一个基于线程池的TaskExecutor。 实际开发中一般是非阻塞的,即异步的,所以我们要在配置类中通过@EnableAsync...
  • 但其实Spring自己也有一个定时任务的实现。不需要引入额外的Jar,使用Spring自带的注解就可以。对于单机非分布式架构用腻了quarts的不妨一试。 简易使用步骤: 在SpringBoot启动类上加上@EnableScheduling注解。...
  • 主要给大家介绍了关于Spring Boot中配置定时任务、线程池与多线程池执行的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用Spring Boot具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
  • spring boot 通过任务执行器 taskexecutor 来实现多线程和并发编程。下面这篇文章主要给大家介绍了关于spring boot中多线程开发的注意事项,文中通过示例代码介绍的非常详细,需要的朋友可以参考下
  • 个用户同时请求一个接口服务的时候,容器会给每一个请求分配一个线程,这时候线程会并发执行该请求所对应的业务逻辑。如果该逻辑涉及到对该单例状态(成员变量)的改变,就会有线程安全的问题。 Spring使用...
  • Spring JDBC-事务管理中的多线程问题

    千次阅读 2017-09-27 04:22:57
    概述 示例 结论 示例源码概述众所周知,Spring 的事务管理器是通过线程相关...我们知道 Web 容器本身就是多线程的,Web 容器为一个 Http 请求创建一个独立的线程,所以由此请求所牵涉到的 Spring 容器中的 Bean 也是运
  • 主要介绍了Spring boot使用多线程过程步骤解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
  • 主要介绍了Spring Boot定时+多线程执行过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
  • 多线程Spring的注入问题

    千次阅读 2019-07-22 20:54:24
    线程中利用@Autowire或者@Resource注入对象,会出现对象为空的情况,如下: @Service public class TestRunnable implements Runnable { @Resource private TestService ts; public TestRunnable...
  • 关于在多线程中使用Spring的事务管理:关于Spring的事务管理:在线程类中添加Spring的事务管理,好像不管用。下面这段代码运行后,有可能抛出异常:“在表中插入重复键值”。我怀疑是UpdateData这个方法并没有作为一...
  • Spring Boot 多线程数据同步

    千次阅读 2020-08-08 17:05:39
    因为最近项目上线,需要同步期初数据-工序,大概有120万数据,采用之前Mybatis批量插入,一次5000的方式,单线程,大概...Spring是通过任务执行器(TaskExecutor)来实现多线程和并发编程,使用ThreadPoolTaskExecutor
  • 主要介绍了spring-boot 多线程并发定时任务的解决方案,需要的朋友可以参考下
  • ssm框架的请移步 https://github.com/zhangtianqing/ssm_ThreadPoolExecutor
  • spring-batch多线程开启

    2021-09-10 16:31:16
    spring-batch优化效率可以直接在step中打开spring多线程,进行多线程运行。当打开多线程之后,十万级的数据运行可以在秒级运行完毕。 打开多线程分两步,1.关闭读取中的状态记录2.开启spring多线程 代码如下 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 251,026
精华内容 100,410
关键字:

多线程spring

spring 订阅