多线程并行threadPool且通过countDownLatch即所谓的闭锁控制线程最终的终止状态 ;方便统计最终处理数 及花费的业务时间
/**
* 首次启动加载数据至缓存
*/
public class ApplicationStartTask {
private static Logger logger = LoggerFactory.getLogger(ApplicationStartTask.class);
private AtomicInteger loadNum = new AtomicInteger(0);
@Autowired
private FaceProducer cacheSynchronizationProducer;
@Autowired
private FaceConsumer cacheSynchronizationConsumer;
@Autowired
private FaceInfoService faceInfoService;
/**
* 当提交一个任务到线程池时,线程池会创建一个线程来执行任务,即使其他空闲的基本线程能够执行新任务也会创建线程,
* <br>等到需要执行的任务数大于线程池基本大小时就不再创建
*/
private static final int POOL_CORE_SIZE = Runtime.getRuntime().availableProcessors();
/**
* 线程池允许创建的最大线程数。如果队列满了,并且已创建的线程数小于最大线程数,则线程池会再创建新的线程执行任务
*/
private static final int POOL_MAX_SIZE = Runtime.getRuntime().availableProcessors();
/**
* 线程池的工作线程空闲后,保持存活的时间 <br>
* 单位:分
*/
private static final int POOL_KEEP_ALIVE_TIME = 2;
@Autowired
@Qualifier("sqliteManagerImpl")
private SqlieteManager sqlieteManager;
@Autowired
private FaceCompareManager faceCompareManager;
@Value("${local.sqlite.sqlname}")
private String sqlName;
@Bean
public ApplicationStartTask loadCache() {
logger.info("[启动任务]首次启动载入数据至缓存...");
checkSqLiteFile();
List<String> belongIds = sqlieteManager.getAllBelongIds();
if (ArrayUtil.isNotEmpty(belongIds)) {
loadFromSqlite(belongIds);
initMqServer();
return new ApplicationStartTask();
}
loadFromDB();
initMqServer();
return new ApplicationStartTask();
}
/**
* 开启MQ服务
*/
private void initMqServer() {
logger.info("开始开启MQ服务...");
cacheSynchronizationProducer.producerStart();
cacheSynchronizationConsumer.getMessage();
}
/**
* 直接从MYSQL载入数据
*/
private void loadFromDB() {
logger.info("当前CPU内核线程数:{}", POOL_CORE_SIZE);
long beginTimsamp = System.currentTimeMillis();
List<String> allBelongId = faceCompareManager.getAllBelongId();
int size = 0;
for (String belongId : allBelongId) {
FaceInfoSyncDataQuery query = new FaceInfoSyncDataQuery(belongId);
query.setPageSize(1000);
query.setDeleteStatus(0);
Result<Integer> result = faceInfoService.getTotalPage(query);
if (!result.isSuccess() || result.getModel() == 0) {
continue;
}
int totalPage = result.getModel();
size += totalPage;
}
logger.info("总任务数:{}", size);
ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(POOL_CORE_SIZE, POOL_MAX_SIZE, POOL_KEEP_ALIVE_TIME,
TimeUnit.MINUTES, new LinkedBlockingQueue<Runnable>(size));
CountDownLatch latch = new CountDownLatch(size);
for (String belongId : allBelongId) {
FaceInfoSyncDataQuery query = new FaceInfoSyncDataQuery();
query.setBelongId(belongId);
query.setDeleteStatus(0);
query.setPageSize(1000);
Result<FaceInfoSyncDataVO> result = faceInfoService.getFaces(query);
if (!result.isSuccess() || result.getModel() == null || result.getModel().getTotalPages() == 0) {
continue;
}
FaceInfoSyncDataVO faceInfoSyncDataVO = result.getModel();
int totalPage = faceInfoSyncDataVO.getTotalPages();
//第一页
poolExecutor.execute(new CacheLoadTask1(1, belongId, faceInfoSyncDataVO.getFaces(), latch));
if (totalPage == 1) {
continue;
}
for (int i = 2; i <= totalPage; i++) {
query = new FaceInfoSyncDataQuery();
query.setBelongId(belongId);
query.setPageSize(1000);
query.setPageNo(i);
query.setDeleteStatus(0);
result = faceInfoService.getFaces(query);
if (!result.isSuccess() || result.getModel() == null || ArrayUtil.isEmpty(result.getModel().getFaces())) {
continue;
}
faceInfoSyncDataVO = result.getModel();
poolExecutor.execute(new CacheLoadTask1(i, belongId, faceInfoSyncDataVO.getFaces(), latch));
}
}
try {
latch.await();// 同步阻塞,直到所有线程工作完成
// long endTime = System.currentTimeMillis(); // 获取结束时间
poolExecutor.shutdown();// 不允许提交新任务,等待当前任务及队列中的任务全部执行完毕后退出
// // 支持等待以前提交的任务停止执行
// // 所有任务关闭请求或线程中断或超时,阻塞取消
// poolExecutor.awaitTermination(20, TimeUnit.MINUTES);
// poolExecutor.shutdownNow();//通过Thread.interrupt试图停止所有正在执行的线程,并不再处理还在队列中等待的任务...
} catch (Exception e) {
logger.error("[启动任务]线程池异常打印:{}", e);
poolExecutor.shutdownNow();
}
// logger.info("[启动任务]从DB中载入数据至缓存完毕!共载入{}条人脸数据", loadNum.get());
logger.info("[启动任务]完毕!全文索引{}条数据,共耗时:{}s", loadNum.get(), (System.currentTimeMillis() - beginTimsamp) / 1000);
}
class CacheLoadTask1 implements Runnable {
private CountDownLatch latch;
List<FaceInfoDO> faceInfoDOs = null;
int putCacheNum = 0;
String belongId = null;
int pageNo = 0;
public CacheLoadTask1(int pageNo, String belongId, List<FaceInfoDO> faceInfoDOs, CountDownLatch latch) {
this.latch = latch;
this.faceInfoDOs = faceInfoDOs;
this.belongId = belongId;
this.pageNo = pageNo;
// this.index = index;
}
@Override
public void run() {
Long beginTime = System.currentTimeMillis();
try {
for (FaceInfoDO faceInfoDO : faceInfoDOs) {
boolean isPutCache = FaceInfoCacheManage.put(faceInfoDO);
if (isPutCache) {
putCacheNum++;
loadNum.incrementAndGet();
}
}
logger.info("[启动任务]线程{}处理完belongId-{}第{}页数据,共载入{}条人脸数据,耗时:{}ms", Thread.currentThread().getName(),
belongId, pageNo, putCacheNum, System.currentTimeMillis() - beginTime);
} catch (Exception e) {
logger.error("[启动任务]载入sqlite任务[CacheLoadTask]出错:{}", e);
} finally {
// TODO: handle finally clause
latch.countDown();
}
}
}
/**
* 从sqlite数据库中加载数据
*/
private void loadFromSqlite(List<String> belongIds) {
logger.info("当前CPU内核线程数:{}", POOL_CORE_SIZE);
ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(POOL_CORE_SIZE, POOL_MAX_SIZE, POOL_KEEP_ALIVE_TIME,
TimeUnit.MINUTES, new LinkedBlockingQueue<Runnable>(belongIds.size()));
CountDownLatch latch = new CountDownLatch(belongIds.size());
for (String belongId : belongIds) {
List<FaceInfoDO> faceInfoDOs = sqlieteManager.selectAllInfoByBelongId(sqlName, belongId);
poolExecutor.execute(new CacheLoadTask(belongId, faceInfoDOs, latch));
}
try {
latch.await();// 同步阻塞,直到所有线程工作完成
// long endTime = System.currentTimeMillis(); // 获取结束时间
logger.info("[启动任务]从sqlite中载入数据至缓存完毕!共载入{}条人脸数据", loadNum.get());
poolExecutor.shutdown();// 不允许提交新任务,等待当前任务及队列中的任务全部执行完毕后退出
// // 支持等待以前提交的任务停止执行
// // 所有任务关闭请求或线程中断或超时,阻塞取消
// poolExecutor.awaitTermination(20, TimeUnit.MINUTES);
// poolExecutor.shutdownNow();//通过Thread.interrupt试图停止所有正在执行的线程,并不再处理还在队列中等待的任务...
} catch (Exception e) {
logger.error("[启动任务]线程池异常打印:{}", e);
poolExecutor.shutdownNow();
}
}
private void checkSqLiteFile() {
File sqliteFile = new File(sqlName + ".sqlite3");
if (!sqliteFile.exists()) {
logger.info("[启动任务]sqlite数据库未创建,开始创建...");
// 第一次启动创建本地表
try {
sqlieteManager.createTable(sqlName);
} catch (Exception e) {
logger.error(e.getMessage());
}
}
}
}