现网被下载(组装数据,输出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>()); }