Spring通过任务执行器(TaskExecutor)来实现多线程和并发编程。使用ThreadPoolTaskExecutor可实现一个基于线程池的TaskExecutor。而实际开发中任务一般是非阻碍的,即异步的,所以我们要在配置类中通过@EnableAsync 开启对异步任务的支持,并通过实际执行Bean的方法中使用@Async注解来声明其是一个异步任务。

示例:

1.配置类。

package com.cnpiec.ireader.config;

import java.util.concurrent.Executor;

import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; @Configuration
@ComponentScan("com.cnpiec.ireader")
@EnableAsync
// 线程配置类
public class AsyncTaskConfig implements AsyncConfigurer { // ThredPoolTaskExcutor的处理流程
// 当池子大小小于corePoolSize,就新建线程,并处理请求
// 当池子大小等于corePoolSize,把请求放入workQueue中,池子里的空闲线程就去workQueue中取任务并处理
// 当workQueue放不下任务时,就新建线程入池,并处理请求,如果池子大小撑到了maximumPoolSize,就用RejectedExecutionHandler来做拒绝处理
// 当池子的线程数大于corePoolSize时,多余的线程会等待keepAliveTime长时间,如果无请求可处理就自行销毁 @Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
taskExecutor.setCorePoolSize(5);// 最小线程数
taskExecutor.setMaxPoolSize(10);// 最大线程数
taskExecutor.setQueueCapacity(25);// 等待队列 taskExecutor.initialize(); return taskExecutor;
} @Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return null;
}
}

2.任务执行类

package com.cnpiec.ireader.service;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.util.List;
import java.util.concurrent.Future; import org.apache.http.HttpEntity;
import org.apache.http.StatusLine;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils; import com.alibaba.fastjson.JSONObject;
import com.cnpiec.ireader.dao.GetBookDataDao;
import com.cnpiec.ireader.model.Book;
import com.cnpiec.ireader.model.Chapter;
import com.cnpiec.ireader.utils.FileNameUtils; @Service
// 线程执行任务类
public class AsyncDownloadBookTaskService { private Logger logger = LoggerFactory.getLogger(AsyncDownloadBookTaskService.class); @Autowired
private GetBookDataDao getBookDataDao; @Async
// 表明是异步方法
// 无返回值
public void executeAsyncTask(List<Book> list, String clientId, String clientSecret) {
System.out.println(Thread.currentThread().getName() + "开启新线程执行");
for (Book book : list) {
String name = book.getName();
File file = new File("iReaderResource/" + name);
if (file.mkdirs()) {
logger.info("文件夹创建成功!创建后的文件目录为:" + file.getPath());
}
try {
getChapterList(book, clientId, clientSecret);
} catch (Exception e) {
logger.error("多线程下载书籍失败:" + book.getBookId(), e);
e.printStackTrace();
}
}
} /**
* 异常调用返回Future
*
* @param i
* @return
* @throws InterruptedException
*/
@Async
public Future<String> asyncInvokeReturnFuture(List<Book> list, String clientId, String clientSecret)
throws InterruptedException { //业务代码
Future<String> future = new AsyncResult<String>("success");// Future接收返回值,这里是String类型,可以指明其他类型 return future;
} /**
* 根据书籍ID获取章节创建文件并写入章节信息
*
* @param book
* @param clientId
* @param clientSecret
* @throws Exception
*/
private void getChapterList(Book book, String clientId, String clientSecret) throws Exception {
String stempSign = clientId + clientSecret + book.getBookId();
String sign = DigestUtils.md5DigestAsHex(stempSign.getBytes());
CloseableHttpClient httpclient = HttpClients.createDefault();
StringBuffer sb = new StringBuffer();
sb.append("http://api.res.ireader.com/api/v2/book/chapterList?").append("bookId=").append(book.getBookId())
.append("&clientId=").append(clientId).append("&sign=").append(sign).append("&resType=json");
HttpGet httpget = new HttpGet(sb.toString());
CloseableHttpResponse response = httpclient.execute(httpget); StatusLine statusLine = response.getStatusLine();
if (statusLine.getStatusCode() == 200) {
HttpEntity entity = response.getEntity();
String result = EntityUtils.toString(entity, "utf-8");
List<Chapter> chapterList = JSONObject.parseArray(result, Chapter.class);
for (Chapter chapter : chapterList) {
File file = new File("iReaderResource/" + book.getName() + "/"
+ FileNameUtils.replaceSpecialCharacters(chapter.getTitle()) + ".txt");
if (file.createNewFile()) {
logger.info("创建章节文件成功:" + file.getPath());
}
String filePath = file.getPath();
getChapterInfo(chapter, book, clientId, clientSecret, filePath); }
getBookDataDao.updateBookStatus(book.getBookId());
} } /**
* 获取章节信息写入文本文件
*
* @param chapter
* @param book
* @param clientId
* @param clientSecret
* @param filePath
* @throws Exception
*/
private void getChapterInfo(Chapter chapter, Book book, String clientId, String clientSecret, String filePath)
throws Exception {
String stempSign = clientId + clientSecret + book.getBookId() + chapter.getChapterId();
String sign = DigestUtils.md5DigestAsHex(stempSign.getBytes());
CloseableHttpClient httpclient = HttpClients.createDefault();
StringBuffer sb = new StringBuffer();
sb.append("http://api.res.ireader.com/api/v2/book/chapterInfo?").append("bookId=").append(book.getBookId())
.append("&chapterId=").append(chapter.getChapterId()).append("&clientId=").append(clientId)
.append("&sign=").append(sign).append("&resType=json");
HttpGet httpget = new HttpGet(sb.toString());
CloseableHttpResponse response = httpclient.execute(httpget); StatusLine statusLine = response.getStatusLine();
if (statusLine.getStatusCode() == 200) {
HttpEntity entity = response.getEntity();
String result = EntityUtils.toString(entity, "utf-8");
Chapter chapter2 = JSONObject.parseObject(result, Chapter.class);
String content = chapter2.getContent();
// 写文件内容
BufferedWriter writer = new BufferedWriter(new FileWriter(new File(filePath), true));
writer.write(content);
writer.close();
}
}
}

3.运行

for (int i = 0; i < list2.size(); i++) {
asyncTaskService.executeAsyncTask(list2.get(i),clientId,clientSecret);
}

SpringBoot 多线程的更多相关文章

  1. springboot 多线程执行

    一.springboot开线程执行异步任务 1.Spring通过任务执行器TaskExecutor,来实现多线程和并发编程,使用ThreadPoolTaskExecutor可实现一个基于线程池的Tas ...

  2. springboot 多线程的使用

    int pageSize = 10000; int totalCount = doctorDAO.selectDatasByMapCount2(jsonArray, false, null); int ...

  3. spring-boot 多线程

    //配置类 package test; import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler; import ...

  4. 玩转SpringBoot之定时任务@Scheduled线程池配置

    序言 对于定时任务,在SpringBoot中只需要使用@Scheduled 这个注解就能够满足需求,它的出现也给我们带了很大的方便,我们只要加上该注解,并且根据需求设置好就可以使用定时任务了. 但是, ...

  5. springboot下多线程开发注意事项

    基于springboot的多线程程序开发过程中,由于本身也需要注入spring容器进行管理,才能发挥springboot的优势.所以这篇文字主要用来记录开发中两者结合时需要注意的一些事项. 第一步我们 ...

  6. 关于java基础、多线程、JavaWeb基础、数据库、SSM、Springboot技术汇总

    作者 : Stanley 罗昊 本人自行总结,纯手打,有疑问请在评论区留言 [转载请注明出处和署名,谢谢!] 一.java基础 1.多态有哪些体现形式? 重写.重载 2. Overriding的是什么 ...

  7. 转载-SpringBoot结合线程池解决多线程问题实录;以及自己的总结

    原文地址:https://blog.csdn.net/GFJ0814/article/details/92422245 看看这篇文章(继续学习):https://www.jianshu.com/p/3 ...

  8. SpringBoot Test 多线程报错:dataSource already closed

    1:前言 最近在项目中使用多线程对大任务拆分处理时,进行数据库操作的时候报错了. 业务代码大概是这样的: @Service public calss TestServiceImpl implement ...

  9. SpringBoot中如何优雅的使用多线程

    SpringBoot中如何优雅的使用多线程 当异步方法有返回值时,如何获取异步方法执行的返回结果呢?这时需要异步调用的方法带有返回值CompletableFuture

随机推荐

  1. POJ-1020-Anniversary Cake

    链接:https://vjudge.net/problem/POJ-1020 题意: 给一个宽为s的正方形,再给n个变长为an的小正方形, 判断是否能将这n个小正方形完全填充到这个大正方形里面. 思路 ...

  2. Codeforces 1143B(思维、技巧)

    自己水平太低,不丢人. 结论是最后选取的数后缀一定是若干个9,暴举即可.然而暴举也有暴举的艺术. ll n; ll dfs(ll n) { if (n == 0) return 1; if (n &l ...

  3. JS中的关系操作符与自动转型

    很多时候对数据操做时都会遇到数据转换,有的是显示转化,有的是隐式转化,即调用默认的规则进行数据转换,经常会把数据转换的方式搞混,于是就花了点时间做了个小小的总结: 一元操作符(--,++,-,+)作用 ...

  4. Retrofit实现Delete请求

    //设置取消关注 @Headers("Content-Type:application/x-www-form-urlencoded") @HTTP(method = "D ...

  5. PM2常用命令

    安装pm2 npm install -g pm2 1.启动 pm2 start app.js pm2 start app.js --name my-api    #my-api为PM2进程名称 pm2 ...

  6. 浅谈Hibernate中的三种数据状态

    Hibernate中的三种数据状态:临时.持久.游离 1.临时态(瞬时态) 不存在于session中,也不存在于数据库中的数据,被称为临时态. 数据库中没有数据与之对应,超过作用域会被JVM垃圾回收器 ...

  7. HTML5+CSS3新增内容总结!!!!!绝对干货

    说到H5C3会不会觉得东西好多啊,今天就整理了一份总结性的内容: CSS3选择器有哪些?答:属性选择器.伪类选择器.伪元素选择器.CSS3新特性有哪些?答:1.颜色:新增RGBA,HSLA模式 文字阴 ...

  8. 前端上传插件Plupload的实际使用(个人实操)

    一个主要的页面,其中包裹了一个iframe页面,在项目中,这个iframe页面包裹在主页面的div标签中,主要用于上传文件附件. 用的是plupload.full插件,主要引入以下几个js: jque ...

  9. Android:Service通知Activity更新界面

    Android有四大组件,其中包括service和activity,那么在使用的过程中,我们最常遇到的问题是他们之间的通信问题. 1.首先Activity调用Service 这个是比较基础的,它有两种 ...

  10. iOS Block的本质(一)

    iOS Block的本质(一) 1.对block有一个基本的认识 block本质上也是一个oc对象,他内部也有一个isa指针.block是封装了函数调用以及函数调用环境的OC对象. 2.探寻block ...