队列和多线程实现异步处理接口数据

本文探讨了如何利用队列和定长线程池实现异步处理下载任务,以解决高CPU占用问题。通过将文件保存在Redis中,避免了并发下的性能瓶颈。同时,建议使用常量和getter、setter方法,而非静态成员变量。文中还讨论了如何验证线程池中始终保持4个线程运行,并指出在大量任务时应使用队列来管理资源,以减少CPU调度开销。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

现网被下载(组装数据,输出excel文件)任务整蹦了(单个任务暂用较高cpu,并发情况下是个无底洞)

研究一下队列和多线程实现异步下载,将文件保存在redis中

package com.lezizx.littlestep.controller;

import com.lezizx.littlestep.test.QueenTest;
import com.lezizx.littlestep.tools.ThreadPoolUtil;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

@RestController
public class QueueController {


    public static BlockingQueue<String> queue = new ArrayBlockingQueue(100);


    @GetMapping("/rest/v1/queenDataIn")
    public String queenDataIn(String queenData){
        if(queue==null){
            queue = new ArrayBlockingQueue(100);
        }
        try {
            //阻塞方法,如果队列满了,此处会阻塞,
            queue.put(queenData);
        }catch (Exception e){
            e.printStackTrace();
        }
        //调用一次消费方法,生成线程消费队列元素
        consumr();
        return queenData;
    }
    //消费信息方法
    public void consumr(){
        //消费数据,队列空了,则不执行任务(很可能其他线程在消费队列信息)
        if(queue!=null && queue.size()>0){
            //采用定长线程池执行任务,此处遍可以控制并发任务执行。
            ThreadPoolUtil.mCachelThreadPool.submit(new Runnable(){
                @Override
                public   void  run(){
                    //处理业务
                    while (true){
                        System.out.println(Thread.currentThread().getName()+"开始执行");
                        try {
                            //此方法也是阻塞的,如果没有获取到会一直阻塞。
                            String model=queue.take();
                            if(model!=null){
                                System.out.println(Thread.currentThread().getName()+"当前读取数据"+model);
                                //处理业务耗时
                                Thread.sleep(5000);
                            }
                            System.out.println("执行完成后,当前队列剩余元素------------"+queue.size());
                        }catch (Exception e){
                            e.printStackTrace();
                        }finally {
                            //每次循环,判断一次队列元素是否已经被执行完了,避免长时间暂用资源
                            if(queue==null||queue.size()==0){
                                queue=null;
                                System.out.println(Thread.currentThread().getName()+"处理完成,队列空了!");
                                break;
                            }
                        }
                    }
                }
            });
        }
    }
}

线程池采用定长线程池,缓存池无限

 

package com.lezizx.littlestep.tools;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadPoolUtil {
//设置为4就是保证并发情况,排着队来处理
   public static ExecutorService mCachelThreadPool = Executors.newFixedThreadPool(4);

}

另:一般不推荐创建静态成员变量,所以最好创建常量,然后写get set方法。

2.19加点东西吧

如何验证是不是一直只有4个线程在跑呢?

线程池创建处加上方法:

public static int getActiveCount(){
    return ((ThreadPoolExecutor)mCachelThreadPool).getActiveCount();
}

其实线程池自身也是一个队列,可以查看构造,里面已经有一个队列在处理业务,所以将消费资产存放在自己的队列中,和存放在多线程的队列中(作为final参数或者构造参数传入一个待的执行线程),都差球不多,所以如果非必要,用不着再创建一个队列来存放元素。

当然这是在消费资产数量不多的情况下。如果是几千上万,还是乖乖用队列吧。毕竟线程是要占用cpu调度和计算的。

public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值