记一次并发工具类countdownlantch 在线程池中的使用
首先 新建一个 ThreadFactory:
package cn.likui.common.thread.pool; import java.util.concurrent.ThreadFactory; import java.util.concurrent.atomic.AtomicInteger; /** * @author lidongge * @Description: * @date 2018/12/25 上午10:23 */ public class NamedThreadFactory implements ThreadFactory { private static final AtomicInteger poolNumber = new AtomicInteger(1); private final ThreadGroup group; private final AtomicInteger threadNumber = new AtomicInteger(1); private final String namePrefix; NamedThreadFactory(String name) { SecurityManager s = System.getSecurityManager(); group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup(); if (null == name || name.isEmpty()) { name = "pool"; } namePrefix = name + "-" + poolNumber.getAndIncrement() + "-thread-"; } @Override public Thread newThread(Runnable r) { Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0); if (t.isDaemon()) { t.setDaemon(false); } if (t.getPriority() != Thread.NORM_PRIORITY) { t.setPriority(Thread.NORM_PRIORITY); } return t; } }
其次 需要定义一个Configuration bean ThreadPoolConfig :
package cn.likui.common.thread.pool; import lombok.extern.slf4j.Slf4j; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.concurrent.ExecutorService; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; /** * @author lidongge * @Description: 自定义线程池 * @date 2018/11/05 上午9:59 */ @Slf4j @Configuration public class ThreadPoolConfig { @Bean public ExecutorService getThreadPool() { ExecutorService es = new ThreadPoolExecutor(3, Integer.MAX_VALUE, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), new NamedThreadFactory("zhangpeng_study")) { @Override public void beforeExecute(Thread t, Runnable r) { super.beforeExecute(t, r); log.info("===》工作线程:{} ,任务线程:{}准备执行",((Thread) r).getName(),t.getName()); } @Override public void afterExecute(Runnable r, Throwable t) { super.afterExecute(r, t); log.info("===》工作线程{}执行完成", ((Thread) r).getName(),t); } @Override public void terminated() { super.terminated(); log.info("===》线程池退出"); } @Override public void execute(Runnable job) { super.execute(wrap(job, clientTrace(), Thread.currentThread().getName())); } //捕获异常 private Runnable wrap(Runnable job, Exception clientTrace, String name) { return new Thread(){ @Override public void run(){ try { job.run(); } catch (Exception e) { log.error("===》线程池中线程执行出现异常:{} ,e:{}", clientTrace,e); } } }; } private Exception clientTrace() { return new Exception("client statck trace"); } }; return es; } }
然后编写自己的 县城处理核心代码:
package cn.likui.common.thread.handle; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import java.util.ArrayList; import java.util.List; import java.util.concurrent.CountDownLatch; /** * @Description: * @Author: lidongge * @Date: 2019/10/29 10:47 */ @Slf4j public class DataHandleService implements Runnable{ /** 接收实际方法调用送来的参数,多个参数支持 */ private CountDownLatch count; private List<Integer> paramList ; public DataHandleService(CountDownLatch count, List paramList){ this.count = count; this.paramList = paramList; } @SneakyThrows @Override public void run() { int j = 0; for (int i =0; i < paramList.size(); i++) { j = j + paramList.get(i); } log.info("本次循环当前线程名称:{},和等于【{}】",Thread.currentThread().getName(),j); count.countDown(); log.info("剩余任务数量:{}", count.getCount()); } }
最后是对该线程池的调用,期间不计算线程执行完后的返回情况
package cn.likui.study.controller; import cn.likui.common.thread.handle.DataHandleService; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; import java.util.ArrayList; import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.TimeUnit; /** * @Description: Demo * @Author: ldg * @Date: 2020/10/10 */ @Slf4j @RestController @RequestMapping("/pool") public class ThreadPoolController { /** 最大线程数*/ private static final int MAX_THREAD_COUNT = 2; @Resource private ExecutorService ex; @RequestMapping("/testThread") @ResponseBody public Object testRestTemplate() throws InterruptedException { // List<Integer> paramList = new ArrayList<>(); for (int i=0; i< 10000; i++) { paramList.add(i); } //等待4个线程 CountDownLatch count = new CountDownLatch(MAX_THREAD_COUNT); //多线程请求执行开始 long startTime = System.currentTimeMillis(); for (int i = 0 ; i < MAX_THREAD_COUNT; i++) { try { //参数一 count,参数二 其他 List<Integer> subList = new ArrayList<>(); if (i == 0) { subList = paramList.subList(0,5000); } else { subList = paramList.subList(5001,9999); } ex.execute(new DataHandleService(count,subList)); } catch (Exception e) { log.error("线程执行中出现异常提前结束", e); count.countDown(); log.error("剩余任务数量:{}", count.getCount()); e.printStackTrace(); } finally { // ex.shutdown(); } } //10秒超时 :超时之前 还未走完线程 会直接走主线 count.await(20, TimeUnit.SECONDS); // ex.shutdown(); long endTime = System.currentTimeMillis(); log.info("多线程打印 耗时:"+ (endTime - startTime) + " ms"); return null; } }
希望写博是我人生坚持在做的事情之一。