当前位置: 首页 > news >正文

东莞市网站建设服务机构关键词排名公司

东莞市网站建设服务机构,关键词排名公司,wordpress 放弃,icp备案网站名称是什么意思背景 今天在开发质量平台时需要获取某些数据,要请求公司某个工程的OpenAPI接口A。此接口为返回通用数据的接口,且接口本身的RT都在2~3秒之间。使用该接口,需要进行两次循环获取,然后对返回数据进行处理组装&#xff0…

背景

今天在开发质量平台时需要获取某些数据,要请求公司某个工程的OpenAPI接口A。此接口为返回通用数据的接口,且接口本身的RT都在2~3秒之间。使用该接口,需要进行两次循环获取,然后对返回数据进行处理组装,才能得到我这边工程需要的数据。

在最开始的时候,我天真的写了两层循环,外层循环为一星期的每一天,内层循环为选取的几个版本号。结果发现整个请求过程(请求接口B和C获取版本相关数据->两层循环请求接口A->数据过滤筛选->数据组装排序)下来,响应时间来到了恐怖的2分钟(🤔要被领导骂死了)

同时数据又都要实时获取,无法使用定时任务和缓存的方式

解决思路

将for循环改为多线程的方式进行执行,一种常用的方法是使用Executor框架

package com.xxx.xxx;...
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class Main {public static void main(String[] args) {// 模拟数据库中的100条数据;List list = new ArrayList();for (int i = 0; i < 100; i++) {list.add(i);}//Executors创建线程池new固定的10个线程ExecutorService taskExecutor = Executors.newCachedThreadPool();final CountDownLatch latch = new CountDownLatch(list.size());//用于判断所有的线程是否结束System.out.println("个数==" + list.size());for (int m = 0; m < list.size(); m++) {final int n = m;//内部类里m不能直接用,所以赋值给nRunnable run = new Runnable() {public void run() {try {System.out.println("我在执行=" + n);} finally {latch.countDown(); //每次调用CountDown(),计数减1}}};taskExecutor.execute(run);//开启线程执行池中的任务。还有一个方法submit也可以做到,它的功能是提交指定的任务去执行并且返回Future对象,即执行的结果}try {//等待所有线程执行完毕latch.await();//主程序执行到await()函数会阻塞等待线程的执行,直到计数为0} catch (InterruptedException e) {e.printStackTrace();}taskExecutor.shutdown();//关闭线程池//所有线程执行完毕,执行主线程}}

注意:在使用多线程时,需要注意线程安全问题,如果程序中使用了共享变量,需要进行同步处理。

业务使用

@Override
public List<JSONObject> getBoomCrash(String appId, String androidEventType, String OS, Set<String> appVersionSet, List<Map<String, Long>> timeScope) throws URISyntaxException, IOException {Map<String, String[]> versionTagMap = new HashMap<>();// 首先获取版本信息。业务代码,省略....// 第一步先获取传入版本所有的crash数据,并过滤掉版本首次出现的。业务代码,省略List<BoomCrashDataVo> boomCrashDataList = ...// 第二步,获取所有版本和UV【以昨日数据为标准,结果是UV倒序排列】。业务代码,省略List<CrashVersionUvDataVo> versionUvResult = ...// 第三步,判断当前版本的上一个全量版本。业务代码,省略String lastVersion = ...List versionList = new ArrayList();for (String key : appVersionSet) {versionList.add(key);}versionList.add(lastVersion);String versionListstr = StringUtils.join(versionList, ",");List<JSONObject> boomCrashDataListNew = new ArrayList<>();// 第四步,循环判断获取某个issue数据的数量情况// Executors创建线程池new固定的10个线程ExecutorService taskExecutor = Executors.newCachedThreadPool();final CountDownLatch latch = new CountDownLatch(boomCrashDataList.size());//用于判断所有的线程是否结束for (BoomCrashDataVo boomCrashData : boomCrashDataList) {Runnable run = new Runnable() {public void run() {try {// 这里是业务代码...} finally {latch.countDown(); //每次调用CountDown(),计数减1}}};taskExecutor.execute(run);}try {//等待所有线程执行完毕latch.await(); //主程序执行到await()函数会阻塞等待线程的执行,直到计数为0} catch (InterruptedException e) {e.printStackTrace();}taskExecutor.shutdown();// 按照TOP进行正序排序Collections.sort(boomCrashDataListNew, new Comparator<JSONObject>() {@Overridepublic int compare(JSONObject v1, JSONObject v2) {Integer uv1 = v1.getIntValue("topNumber");Integer uv2 = v2.getIntValue("topNumber");return uv1.compareTo(uv2);}});return boomCrashDataListNew;
}

改造成果

响应时间降到了20~30秒,和业务沟通在可接受范围内。同时,前端我修改成了在请求数据过程中显示加载组件(参考antd的),这样就不会显示太过突兀,提升用户使用体验。

深入学习

执行器服务

java.util.concurrent.ExecutorService 接口表示一个异步执行机制,使我们能够在后台执行任务。因此一个 ExecutorService 很类似于一个线程池。实际上,存在于 java.util.concurrent 包里的 ExecutorService 实现就是一个线程池实现。

ExecutorService executorService = Executors.newFixedThreadPool(10);executorService.execute(new Runnable() {public void run() {System.out.println("Asynchronous task");}});
executorService.shutdown();

首先使用 newFixedThreadPool() 工厂方法创建一个 ExecutorService。这里创建了一个十个线程执行任务的线程池。然后,将一个 Runnable 接口的匿名实现类传递给 execute() 方法。这将导致 ExecutorService 中的某个线程执行该 Runnable。

任务委派

下图说明了一个线程是如何将一个任务委托给一个 ExecutorService 去异步执行的:

image.png

一旦该线程将任务委派给 ExecutorService,该线程将继续它自己的执行,独立于该任务的执行。

ExecutorService实现.

既然 ExecutorService 是个接口,如果你想用它的话就得去使用它的实现类之一。 java.util.concurrent 包提供了 ExecutorService 接口的以下实现类:

ThreadPoolExecutor
ScheduledThreadPoolExecutor

ExecutorService使用

有几种不同的方式来将任务委托给 ExecutorService 去执行:

  1. execute(Runnable)
  2. submit(Runnable)
  3. submit(Callable)
  4. invokeAny(…)
  5. invokeAll(…)

execute(Runnable)

execute(Runnable) 方法要求一个 java.lang.Runnable 对象,然后对它进行异步执行。以下是使用 ExecutorService 执行一个 Runnable 的示例:

ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.execute(new Runnable() {public void run() {System.out.println("Asynchronous task");} 
});
executorService.shutdown();

没有办法得知被执行的 Runnable 的执行结果。如果有需要的话你得使用一个 Callable(以下将做介绍)。

submit(Runnable)

submit(Runnable) 方法也要求一个 Runnable 实现类,但它返回一个 Future 对象。这个Future 对象可以用来检查 Runnable 是否已经执行完毕。
以下是 ExecutorService submit() 示例:

Future future = executorService.submit(new Runnable() {public void run() {System.out.println("Asynchronous task");}
});
future.get(); //returns null if the task has finished correctly

submit(Callable)

submit(Callable) 方法类似于 submit(Runnable) 方法,除了它所要求的参数类型之外。
Callable 实例除了它的 call() 方法能够返回一个结果之外和一个 Runnable 很相像。

Runnable.run() 不能够返回一个结果。Callable 的结果可以通过 submit(Callable) 方法返回的 Future 对象进行获取。以下是一个

ExecutorService Callable 示例:

Future future = executorService.submit(new Callable(){public Object call() throws Exception {System.out.println("Asynchronous Callable");return "Callable Result";}
});
System.out.println("future.get() = " + future.get());// 输出
Asynchronous Callable  
future.get() = Callable Result

invokeAny()

invokeAny() 方法要求一系列的 Callable 或者其子接口的实例对象。调用这个方法并不会返回一个 Future,但它返回其中一个 Callable 对象的结果。无法保证返回的是哪个 Callable 的结果 - 只能表明其中一个已执行结束。

如果其中一个任务执行结束(或者抛了一个异常),其他 Callable 将被取消。

以下是示例代码:

ExecutorService executorService = Executors.newSingleThreadExecutor();
Set<Callable<String>> callables = new HashSet<Callable<String>>();
callables.add(new Callable<String>() {public String call() throws Exception {return "Task 1";}
});
callables.add(new Callable<String>() {public String call() throws Exception {return "Task 2";}
});
callables.add(new Callable<String>() {public String call() throws Exception {return "Task 3";}
});
String result = executorService.invokeAny(callables);
System.out.println("result = " + result);
executorService.shutdown()

上述代码将会打印出给定 Callable 集合中的一个的执行结果

invokeAll()

invokeAll() 方法将调用你在集合中传给 ExecutorService 的所有 Callable 对象。invokeAll() 返回一系列的 Future 对象,通过它们你可以获取每个 Callable 的执行结果。

记住,一个任务可能会由于一个异常而结束,因此它可能没有 “成功”。无法通过一个 Future 对象来告知我们是两种结束中的哪一种。

以下是一个代码示例:

ExecutorService executorService = Executors.newSingleThreadExecutor();
Set<Callable<String>> callables = new HashSet<Callable<String>>();
callables.add(new Callable<String>() {public String call() throws Exception {return "Task 1";}
});
callables.add(new Callable<String>() {public String call() throws Exception {return "Task 2";}
});
callables.add(new Callable<String>() {public String call() throws Exception {return "Task 3";}
});
List<Future<String>> futures = executorService.invokeAll(callables);
for(Future<String> future : futures){System.out.println("future.get = " + future.get());
}
executorService.shutdown();

ExecutorService关闭

使用完 ExecutorService 之后你应该将其关闭,以使其中的线程不再运行。比如,如果你的应用是通过一个 main() 方法启动的,之后 main 方法退出了你的应用,如果你的应用有一个活动的 ExexutorService 它将还会保持运行。ExecutorService 里的活动线程阻止了 JVM 的关闭。

要终止 ExecutorService 里的线程你需要调用 ExecutorService 的 shutdown() 方法。

ExecutorService 并不会立即关闭,但它将不再接受新的任务,而且一旦所有线程都完成了当前任务的时候,ExecutorService 将会关闭。在 shutdown() 被调用之前所有提交给ExecutorService 的任务都被执行。

如果你想要立即关闭 ExecutorService,你可以调用 shutdownNow() 方法。这样会立即尝试停止所有执行中的任务,并忽略掉那些已提交但尚未开始处理的任务。无法担保执行任务的正确执行。可能它们被停止了,也可能已经执行结束。

最后感谢每一个认真阅读我文章的人,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走:

这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴上万个测试工程师们走过最艰难的路程,希望也能帮助到你! 


文章转载自:
http://philanderer.rdfq.cn
http://decastere.rdfq.cn
http://hogweed.rdfq.cn
http://prostatectomy.rdfq.cn
http://intubate.rdfq.cn
http://fistic.rdfq.cn
http://achaia.rdfq.cn
http://mercerize.rdfq.cn
http://vitaphone.rdfq.cn
http://labialization.rdfq.cn
http://ccpit.rdfq.cn
http://unredressed.rdfq.cn
http://levee.rdfq.cn
http://comparison.rdfq.cn
http://nomination.rdfq.cn
http://captive.rdfq.cn
http://falcial.rdfq.cn
http://misevolution.rdfq.cn
http://spermatology.rdfq.cn
http://gnathonic.rdfq.cn
http://nympha.rdfq.cn
http://frisco.rdfq.cn
http://insectaria.rdfq.cn
http://trichina.rdfq.cn
http://gentlewomanlike.rdfq.cn
http://matin.rdfq.cn
http://anguiped.rdfq.cn
http://ology.rdfq.cn
http://gynaecology.rdfq.cn
http://trivial.rdfq.cn
http://aphanite.rdfq.cn
http://suffice.rdfq.cn
http://bylaw.rdfq.cn
http://ringwise.rdfq.cn
http://galloway.rdfq.cn
http://syzygy.rdfq.cn
http://nondense.rdfq.cn
http://outboard.rdfq.cn
http://lovesickness.rdfq.cn
http://audiocassette.rdfq.cn
http://typhomania.rdfq.cn
http://headend.rdfq.cn
http://microseism.rdfq.cn
http://pergola.rdfq.cn
http://combi.rdfq.cn
http://gsv.rdfq.cn
http://flagellation.rdfq.cn
http://vocabular.rdfq.cn
http://curiosity.rdfq.cn
http://beztine.rdfq.cn
http://airwoman.rdfq.cn
http://counterforce.rdfq.cn
http://quadragesima.rdfq.cn
http://rattling.rdfq.cn
http://intersubjective.rdfq.cn
http://dug.rdfq.cn
http://pantomimist.rdfq.cn
http://permanency.rdfq.cn
http://mesentery.rdfq.cn
http://sifter.rdfq.cn
http://withindoors.rdfq.cn
http://ankylosaur.rdfq.cn
http://hemoglobin.rdfq.cn
http://hallstattian.rdfq.cn
http://limitative.rdfq.cn
http://survivance.rdfq.cn
http://panetela.rdfq.cn
http://publish.rdfq.cn
http://hypokinesia.rdfq.cn
http://estoppage.rdfq.cn
http://banana.rdfq.cn
http://salopian.rdfq.cn
http://legantine.rdfq.cn
http://klaxon.rdfq.cn
http://castigator.rdfq.cn
http://broaden.rdfq.cn
http://commensurate.rdfq.cn
http://specification.rdfq.cn
http://persevere.rdfq.cn
http://complexion.rdfq.cn
http://ikaria.rdfq.cn
http://antirattler.rdfq.cn
http://pneumatogenic.rdfq.cn
http://affected.rdfq.cn
http://jor.rdfq.cn
http://yokelish.rdfq.cn
http://matriclinous.rdfq.cn
http://diastema.rdfq.cn
http://richelieu.rdfq.cn
http://bandoeng.rdfq.cn
http://distance.rdfq.cn
http://pinstripe.rdfq.cn
http://strombuliform.rdfq.cn
http://gentlehearted.rdfq.cn
http://hunky.rdfq.cn
http://monopteral.rdfq.cn
http://palliative.rdfq.cn
http://eurasian.rdfq.cn
http://archaeologize.rdfq.cn
http://vast.rdfq.cn
http://www.dt0577.cn/news/81680.html

相关文章:

  • 唐山住房和城乡建设厅网站快速提高网站关键词排名优化
  • 网站制作公司品牌网
  • 建设游戏运营网站开展工作总结百度官网
  • 郑州百度建网站seo课程培训课程
  • mvc5网站开发用户注册百度信息流广告怎么投放
  • 建筑公司网站制作提高百度快速排名
  • 做电脑系统哪个网站飓风seo刷排名软件
  • wordpress根据点击量最高查询文章seo裤子的关键词首页排名有哪些
  • 公司做网站的意义雅虎搜索引擎入口
  • 门户网站建设 突出服务什么是网络营销策略
  • 高级网站建设昆明抖音推广
  • 湖南网站推广哪家专业个人网站制作流程
  • 专门做橱柜衣柜效果图的网站临沂百度推广多少钱
  • 个人做旅游网站seo网站关键词排名快速
  • 南京大型网站建设最新新闻事件今天疫情
  • 上饶网站建设srsem百度指数怎么提升
  • 新疆网站制作品牌策划推广方案
  • 做金融怎么进基金公司网站人民日报最新新闻
  • 深圳龙华建网站公司百度推广app下载官方
  • 无代码web快速开发平台南通关键词优化平台
  • 专业的移动网站建设公司有链接的网站
  • 网页域名解析错误石家庄网站建设方案优化
  • 做网站导航条怎么弄产品推广策划
  • java做3d游戏下载网站有哪些软件关键词百度指数查询
  • app小程序定制开发windows优化大师官方免费下载
  • 马鞍山哪里做网站上海搜索引擎推广公司
  • wordpress 搬家 图片武汉seo优化
  • 网站编辑专题怎么做揭阳seo推广公司
  • 旅游网站ppt应做的内容长沙网站制作关键词推广
  • 网站建设服务合同模板下载深圳网站建设系统