SpringBoot项目使用多线程对项目进行优化

文章介绍了如何在SpringBoot应用中配置多线程,包括在`application.yaml`设置线程池参数,使用`@EnableAsync`启用异步方法,以及在Service层实现异步操作。同时,针对并发时的数据一致性问题,文中提到了使用悲观锁和编程式事务管理来确保数据完整性。
摘要由CSDN通过智能技术生成

一、在application.yaml中进行多线程的配置

#多线程配置
  task:
    execution:
      pool:
        core-size: 20
        max-size: 1000
        keep-alive: 60000
        queue-capacity: 1000
      thread-name-prefix: ehub
配置相关参数解释:
  1. core-size:核心线程数

  1. max-size:最大线程数

  1. keep-alive:空闲线程能存活的最长时间

  1. queue-capacity:队列最大程度

  1. thread-name-prefix:线程名

二、在启动类中加入@EnableAsync注解,允许开启异步

@EnableAsync
@SpringBootApplication
public class EhubApplication {

    public static void main(String[] args) {
        SpringApplication.run(EhubApplication.class, args);
    }

}

三、service层添加对应接口,但是不能有返回值,如果需要返回值需要callback方法

public interface EhubService {
    //下载阿里云OSS存储文件并进行分析后存入数据库中
    void downOSS();

    //打印文件与文件夹结果
    void print() throws IOException;
}

四、在该service对应的实现类中使用@Async而不是使用@override,表示对于相对应的类或方法开启异步调用

@Service
public class EhubServiceImpl implements EhubService{
    @Autowired
    DocumentMapper documentMapper;
    @Autowired
    FolderMapper folderMapper;

    // Endpoint为华东1(杭州)
    public static String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
    // 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。
    public static String accessKeyId = "LTAI5tRMrh1tg3inWY6nsBC5";
    public static String accessKeySecret = "RYDOCkLifanjuXujtMnOscoOducCUO";
    // Bucket名称
    public static String bucketName = "56linked-test";

    @Async
    //下载阿里云OSS存储文件并进行分析后存入数据库中
    public void  downOSS(){
        
    }
}

注意:在使用多线程时,一定要注意使用synchronized所标注的同步方法或同步代码块。当你使用了synchronized之后,即便你创建了线程池,各个线程也会等待其中一个线程执行同步方法或同步代码块之后才会执行。简而言之:多线程无效,无法提高效率。

解决方法:在本次项目中我使用了悲观锁(在SQL语句最后加入:for update)并使用编程式事务控制对每一个事务进行回滚,保证了数据的一致性。

                        //编程式事务
                        DefaultTransactionDefinition defaultTransactionDefinition = new DefaultTransactionDefinition();
                        defaultTransactionDefinition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
                        TransactionStatus transactionStatus = transactionManager.getTransaction(defaultTransactionDefinition);
                        try {
                            //判断数据库中是否有该文件夹(文件夹名相同且路径相同)
                            Folder folder = folderMapper.findFolderByName(name, path);
                            if (folder != null) {//如果有:更新文件夹大小,所含文件数+1;
                                folder.setFolderSize(folder.getFolderSize() + s.getSize());
                                folder.setFolderNumberOfFiles(folder.getFolderNumberOfFiles() + 1);
                                //之后查询该文件夹所含文件夹路径中是否含有文件夹完整路径,如果没有:所含文件夹数+1
                                String b[] = folder.getFolderPathOfFolders().split(",");
                                if (!Arrays.asList(b).contains(path1) && path1 != "最后一级文件夹") {
                                    folder.setFolderNumberOfFolders(folder.getFolderNumberOfFolders() + 1);
                                    //添加该目录
                                    folder.setFolderPathOfFolders(folder.getFolderPathOfFolders() + "," + path1);
                                }
                                //更新至数据库
                                folderMapper.upDateFolder(folder);
                            } else { //如果没有(添加新文件夹):更新文件夹大小,所含文件数+1,添加所属路径。最后存入folder表中
                                //通过构造函数进行赋值
                                Folder folder1 = new Folder(name, s.getSize(), 1, 0, "", path);
                                //对path进行拆分,对每一级的文件文件夹所含文件夹数量加一
                                String b[] = path.split("/");
                                String path2 = "";
                                for (int j = 0; j < b.length; j++) {
                                    if (j > 0) {
                                        path2 = path2 + b[j - 1] + "/";
                                    }
                                    if (j < b.length - 1) {
                                        //更新数据
                                        Folder folder2 = folderMapper.findFolderByName(b[j], path2);
                                        folder2.setFolderNumberOfFolders(folder2.getFolderNumberOfFolders() + 1);
                                        //保存至数据库
                                        folderMapper.deleteById(Math.toIntExact(folder2.getFolderId()));
                                        folderMapper.insert(folder2);
                                    }
                                }
                                //保存至数据库
                                folderMapper.insert(folder1);
                            }
                            transactionManager.commit(transactionStatus);
                        } catch (Exception e) {
                            log.error("xxxx", e);
                            transactionManager.rollback(transactionStatus);
                        }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Kblzxj

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值