⭐⭐⭐ Spring Boot 项目实战 ⭐⭐⭐ Spring Cloud 项目实战
《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 blog.csdn.net/qililong88/article/details/114320641 「qililong88」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注**微信公众号:【芋道源码】**有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言将得到认真回复。甚至不知道如何读源码也可以请教噢
  4. 新的源码解析文章实时收到通知。每周更新一篇左右
  5. 认真的源码交流微信群。

有一个大List集合,遍历进行一些耗时操作,不能达到性能要求,查询日志,单个任务虽然有不少数据库和第三方API请求,比较耗时,但返回效率尚可,所以优先采用多线程方式进行处理并行请求数据库和第三方API,因为处理完还要对list所属的数据进行操作,所以,线程池多线程处理要等待全部处理完。

相关的代码如下:

@Test
public void testTB()
{
List < String > list = new ArrayList < > ();
for(int i = 0; i < 900; i++)
{
list.add("a");
}
ExecutorService touchWorker = Executors.newFixedThreadPool(4, new ThreadFactoryBuilder().setNameFormat("touch-send-worker-%d").build());
int size = list.size();
if(size > 100)
{
int batch = size % 100 == 0 ? size / 100 : size / 100 + 1;
for(int j = 0; j < batch; j++)
{
int end = (j + 1) * 100;
if(end > size)
{
end = size;
}
List < String > subList = list.subList(j * 100, end);
touchWorker.execute(() - > sleepTest(subList));
}
touchWorker.shutdown();
while(true)
{
if(touchWorker.isTerminated())
{
break;
}
}
}
else
{
sleepTest(list);
}
}
private void sleepTest(List < String > subList)
{
for(String i: subList)
{
try
{
//耗时操作
System.out.println("######" + i + "######" + Thread.currentThread().getName());
// Thread.sleep(1000*30);
}
catch(Exception e)
{
e.printStackTrace();
}
}
}

void shutdown()

启动一次顺序关闭,执行以前提交的任务,但不接受新任务。若已经关闭,则调用没有其他作用。

抛出:SecurityException - 如果安全管理器存在并且关闭,此 ExecutorService 可能操作某些不允许调用者修改的线程(因为它没有保持RuntimePermission("modifyThread")),或者安全管理器的 checkAccess 方法拒绝访问。

boolean isTerminated()

若关闭后所有任务都已完成,则返回true。注意除非首先调用shutdownshutdownNow,否则isTerminated永不为true。返回:若关闭后所有任务都已完成,则返回true。

当然还有一种方法,是之前写的,方法比上边的臃肿了,不过会获取返回结果进行处理:逻辑是获取所有页面的List,多线程遍历List后,将所有页面的违规词查出发送邮件,代码:

/**
* 落地页违规词排查(多线程)。
* @return
*/
@Test
public void getViolationsLandpageByThreadPool() {
try {
landPageService.getViolationsLandpageByThreadPool("1年");
} catch (Exception e) {
e.printStackTrace();
}
}

// 开始时间
long start = System.currentTimeMillis();
/*List<LandPage> list = new ArrayList<LandPage>();
for (int i = 1; i <= 3000; i++) {
list.add(i + "");
}*/

List<LandPage> list = landPageDao.getPageIdAndPath();
// 初始化敏感词库对象
SensitiveWordInit sensitiveWordInit = new SensitiveWordInit();
// 从数据库中获取敏感词对象集合(目前先放在资源文件中,等以后比较多或者需要界面操作时再用数据库)
// 构建敏感词库
Map sensitiveWordMap = sensitiveWordInit.initKeyWord(vioKey);
// 传入SensitivewordEngine类中的敏感词库
SensitivewordEngine.sensitiveWordMap = sensitiveWordMap;
// 每500条数据开启一条线程
int threadSize = 11000;
// 总数据条数
int dataSize = list.size();
// 线程数
int threadNum = dataSize / threadSize + 1;
// 定义标记,过滤threadNum为整数
boolean special = dataSize % threadSize == 0;

/*list.parallelStream().forEach(url ->{});*/
// 创建一个线程池
ExecutorService exec = Executors.newFixedThreadPool(threadNum);
// 定义一个任务集合
List<Callable<List<LandPage>>> tasks = new ArrayList<Callable<List<LandPage>>>();
Callable<List<LandPage>> task = null;
List<LandPage> cutList = null;

// 确定每条线程的数据
for (int i = 0; i < threadNum; i++) {
if (i == threadNum - 1) {
if (special) {
break;
}
cutList = list.subList(threadSize * i, dataSize);
} else {
cutList = list.subList(threadSize * i, threadSize * (i + 1));
}
// System.out.println("第" + (i + 1) + "组:" + cutList.toString());
final List<LandPage> listStr = cutList;
task = new Callable<List<LandPage>>() {

@Override
public List<LandPage> call() throws Exception {
// System.out.println(Thread.currentThread().getName() + "线程:" + listStr.get(0).getPageId());
List<LandPage> result = new ArrayList<LandPage>();
for (LandPage landPage : listStr) {
Long pageId = landPage.getPageId();
String path = landPage.getPath();
Integer version = landPage.getVersion();
String pageUrl = landPage.getPageUrl();
String actualUser = landPage.getActualUser();
Integer pageType = landPage.getPageType();
if (StringUtils.isNotBlank(path)) {
// 调用第一个方法,获取html字符串
String html = httpRequest(path);
// 调用第二个方法,获取包含的违规词
if(StringUtils.isNotBlank(html)){
html = html.replaceAll("<!--(.*?)-->","");
// String buffer = htmlFiter2(html);
Set<String> bufferSet = SensitivewordEngine.getSensitiveWord(html, 1);// 得到敏感词有哪些,传入2表示获取所有敏感词//sensitiveWordFiltering(html);
/*String[] word = {"备案","错过将延误","仅需1980元"};
for(int i=0 ;i<word.length;i++){
if(html.contains(word[i])){
bufferSet.add(word[i]);
}
}*/
String[] word = {
"一年","1年学完","一年学完","1年内学完","一年内学完"
};
for(int i=0 ;i<word.length;i++){
if(html.contains(word[i])){
bufferSet.add(word[i]);
}
}
if (null!=bufferSet&&bufferSet.size()>0) {

String sensitiveWord = bufferSet == null ? null : bufferSet.toString();
if ("[]".equals(sensitiveWord)){
sensitiveWord = "";
}
LandPage page = new LandPage();
page.setPageId(pageId);
page.setPath(path);
page.setVersion(version);
page.setDescription(sensitiveWord);
page.setPageUrl(pageUrl);
page.setActualUser(actualUser);
page.setPageType(pageType);
result.add(page);
System.out.println(pageUrl);
}
}
}
}
return (List<LandPage>) result;
}
};
// 这里提交的任务容器列表和返回的Future列表存在顺序对应的关系
tasks.add(task);
}

List<Future<List<LandPage>>> results = exec.invokeAll(tasks);
List<LandPage> result = new ArrayList<LandPage>();
for (Future<List<LandPage>> future : results) {
result.addAll(future.get());
}

// 关闭线程池
exec.shutdown();
System.out.println("线程任务执行结束");
System.err.println("执行任务消耗了 :" + (System.currentTimeMillis() - start) + "毫秒");

System.out.println("共有###########"+list.size() );

result就是需要发送邮件的相关结果了

文章目录
  1. 1. void shutdown()
  2. 2. boolean isTerminated()