多线程实例

傷城~ 2023-07-10 11:27 96阅读 0赞

场景如下

有多个品牌,每个品牌下有多个商品,现在要过滤掉其中没有商品的品牌。

除了没有商品的可能,还有用户被屏蔽的可能,因此还有一道过滤逻辑。

比如康师傅品牌下有康师傅红茶、康师傅方便面等等,盼盼品牌下啥也没有,就要把盼盼过滤掉,康师傅留下。

过滤的线程如下

  1. //得到品牌下商品的个数
  2. class CountGoods implements Callable<Integer>{
  3. //分页参数
  4. PageRequest request;
  5. //品牌id
  6. Long brandId;
  7. //所有品牌列表,如果传入的品牌无效,就将此列表的该品牌去掉
  8. CopyOnWriteArrayList<Long> brandList;
  9. public CountGoods(PageRequest request, Long brandId, CopyOnWriteArrayList<Long> brandList){
  10. this.request = request;
  11. this.brandId = brandId;
  12. this.brandList = brandList;
  13. }
  14. @Override
  15. public Integer call() throws Exception{
  16. //获取所有品牌下商品
  17. Map<Long,List<Long>> brandSkuMap = getBrand(request.getBpin());
  18. //获取该品牌下的商品
  19. List<Long> subSkuList = brandSkuMap.get(fBrandId);
  20. //防止空数据
  21. if(subSkuList == null){
  22. return 0;
  23. }
  24. //对该品牌下的商品进行过滤
  25. List<GoodsInfo> goodsInfo= goodsRpc.synFilterSku(request.getBpin(), subSkuList);
  26. if(goodsInfo== null){
  27. return 0;
  28. }else{
  29. if(goodsInfo.size() == 0){
  30. brandList.remove(brandId);
  31. }
  32. return goodsInfo.size();
  33. }
  34. }
  35. }

多线程进行过滤

  1. public List<Long> filterBrandList(PageRequest request, List<Long> IdList){
  2. List<Callable<Integer>> calls = new ArrayList();
  3. //过滤逻辑
  4. Iterator<Long> iterator = IdList.iterator();
  5. while(iterator.hasNext()){
  6. Long brandId =iterator.next();
  7. Callable call = new countId(request, brandId , (CopyOnWriteArrayList<Long>) IdList);
  8. calls.add(call);
  9. }
  10. ExecutorService cacheThreadPool = new ThreadPoolExecutor(5, 10, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>());
  11. List<Future<Integer>> callableResult = null;
  12. try{
  13. if(calls != null && calls.size() > 0){
  14. callableResult = cacheThreadPool.invokeAll(calls);
  15. }
  16. }catch (Exception e){
  17. e.printStackTrace();
  18. LogUtil.printErrorLog(log, "多线程过滤品牌出现异常");
  19. }finally {
  20. cacheThreadPool.shutdown();
  21. }
  22. return fontBrandIdList;
  23. }

缺陷

毫无疑问,这段代码一上到线上运行,就出了bug。

报错很奇怪,说是执行线程时,执行线程里的过滤操作出错了,但是有部分是执行成功。

百思不得其姐,终于周末想到一个问题,我似乎没给它阻塞队列……

注意了,这个线程池的阻塞队列有问题,需要修改,这样只能有10个任务过来,更多的会被拒绝。修改线程池的阻塞队列类型即可。

  1. new SynchronousQueue<Runnable>()

这个是没有阻塞队列的意思。

修改如下:

  1. ExecutorService cacheThreadPool = new ThreadPoolExecutor(5, 10, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(100))

但是还有一个问题:

注意了,这样将线程池直接在service方法中new出来是不对的,因为这样没法复用线程。比如,两个人同时访问这个方法,就分别new了一个线程池,没有用同一个线程池,而且,如果并发很高,线程数量激增,很可能会挂掉。应该给个static的线程池,或者单独写一个线程池的bean,在所有地方复用。

发表评论

表情:
评论列表 (有 0 条评论,96人围观)

还没有评论,来说两句吧...

相关阅读

    相关 线实例

    场景如下 有多个品牌,每个品牌下有多个商品,现在要过滤掉其中没有商品的品牌。 除了没有商品的可能,还有用户被屏蔽的可能,因此还有一道过滤逻辑。 比如康师傅品牌下有康师