项目中遇到一个需要批量更新数据的需求,要求将实时传过来的数据实时更新到数据库中
一开始只是简单的调用mapper的更新接口,没啥问题,后期发现数据太多一直在请求接口,数据无法实时更新到数据库中,后来引入了线程池解决了这个问题
线程池–基于池话思想的线程管理工具,用户无需关注如何创建、调度线程来执行任务,用户只需提供 Runnable、Thread对象,将任务的运行逻辑提交到run方法中,由线程池完成线程的调配和任务的执行部分,这样带来的好处是减少了线程线程创建、销毁的开销,避免了线程数量过多导致的内存占用问题,极大的提高了资源利用率、响应速度
七大参数:
corePoolSize 核心线程数目
maximumPoolSize 最大线程数目
keepAliveTime 生存时间
unit 时间单位
workQueue 工作队列
threadFactory 线程工厂
handler 拒绝策略 - 当所有线程都在繁忙,workQueue 也放满时,会触发拒绝策略。
(1)抛异常 java.util.concurrent.ThreadPoolExecutor.AbortPolicy。
(2)由调用者执行任务 java.util.concurrent.ThreadPoolExecutor.CallerRunsPolicy。
(3)丢弃任务 java.util.concurrent.ThreadPoolExecutor.DiscardPolicy。
(4)丢弃最早排队任务 java.util.concurrent.ThreadPoolExecutor.DiscardOldestPolicy
线程池的执行流程
1)、如果当前运行的线程少于 corePoolSize,则创建新线程来执行任务。
2)、如果运行的线程等于或大余 corePoolSize,则将任务加入 阻塞队列BlockingQueue中。
3)、如果无法将任务加入BlockingQueue(队列已满),则创建新的线程来处理任
4)、如果创建新线程将使当前运行的线程超过 maximumPoolSize,任务将被拒绝,并调用RejectedExecutionHandler.rejectedExecutor() 方法。
线程类:需要外界提供service和相应的数据map
public class CameraThreadHandler extends Thread{
private NewLocatorService newLocatorService;
private Map<String, List<Map<String,Integer>>> map;
public CameraThreadHandler(NewLocatorService newLocatorService,Map<String, List<Map<String,Integer>>> map){
this.newLocatorService = newLocatorService;
this.map = map;
}
@Override
public void run() {
newLocatorService.storeCameraInfo(map);
}
}
线程关联类,暂且这样称呼,为线程提供初始化数据
@Autowired
private NewLocatorService newLocatorService;
private ExecutorService executorService =
new ThreadPoolExecutor(5, 10, 1000, TimeUnit.MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10), new ThreadPoolExecutor.DiscardOldestPolicy());
@ServiceActivator(inputChannel = "udpHandle1")
public void udpMessageHandle(String message) throws Exception {
try {
ObjectMapper objectMapper = new ObjectMapper();
Map<String, List<Map<String,Integer>>> map = new HashMap<>();
executorService.execute(new CameraThreadHandler(newLocatorService,objectMapper.readValue(message, map.getClass())));
log.info("message:" + message);
}catch (Exception e){
e.printStackTrace();
//return R.error();
}
}
补充一点,数据初始化,可直接注入后传值,
@Slf4j
@Configuration
public class SpringContextUtil implements ApplicationContextAware {
// Spring应用上下文环境
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
public static <T> T getBean(String beanId) {
T bean = null;
try {
if (StringUtils.isNotEmpty(StringUtils.trim(beanId))) {
bean = (T) applicationContext.getBean(beanId);
}
} catch (NoSuchBeanDefinitionException e) {
log.error("获取bean失败");
return null;
}
return bean;
}
public static <T> T getBean(String... partName) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < partName.length; ++i) {
sb.append(partName[i]);
if (i != partName.length - 1) {
sb.append(".");
}
}
return getBean(sb.toString());
}
}