线程池+队列实现日志定时批量提交日志

最近有个需求需要记录用户操作记录,实现起来无非是用aop直接记录日志。用自定义注解,通过属性文件建立注解和具体操作的映射关系,然后用aop切入持有该注解的接口,记录操作信息。
这种在并发不高的系统上是可行的,一旦并发量略高,aop里的插入DB操作势必会影响接口响应时间,对性能影响还是有一些的。因此将其改为系统定时批量插入日志,模拟一个简单的mq,下面直接贴代码。具体实现全写在注释里了。

//@Component
public class TaskThreadPools {
    @Autowired
    private ManagerService managerService;
    @Autowired
    private OperationLogService operationLogService;

    private static final org.apache.commons.logging.Log log = LogFactory.getLog(TaskThreadPools.class);
    //线程池对队列的操作可能并发,需要volatile保证队列内存可见性
    private static volatile Queue<QueueDealStructure> dataQueue;
    private volatile List<OperationLog> logs = Collections.synchronizedList(new ArrayList<>());

    public static Queue<QueueDealStructure> getQueueInstance() {
        if (dataQueue == null) {
            //LinkedList实现了Queue接口,可以用LinkedList做一个队列,这里使用阻塞队列BlockingQueue
            dataQueue = new LinkedBlockingQueue<>();
        }
        return dataQueue;
    }

    public void commitLogPool() {
        /**
        *@Author hfismyangel@163.com
        *@Description:定时任务线程池自动提交日志
        *@Date: 20:01 2017/10/13
           * @param
        */
        if (getQueueInstance().peek() != null) {
            log.info("===================poll is not null,make Executor>>");
            int size;
            //初始化固定容量为队列长度的Executor
            ExecutorService threadPoolExecutor = Executors.newFixedThreadPool((size = getQueueInstance().size()));

            for (int i = 0; i < size; i++) {
                threadPoolExecutor.submit(new Runnable() {
                    @Override
                    public void run() {
                        QueueDealStructure poll;
                        if ((poll = getQueueInstance().poll()) != null) {
                            try {
                                String keyIdentity = poll.getKeyIdentity();
                                String property = poll.getProperty();
                                log.info("===================thread start and Thread id>>" + Thread.currentThread().getId());
                                Long adminId = Long.valueOf(keyIdentity);
                                Manager admin = managerService.getObjectById(adminId);
                                //创建日志对象
                                OperationLog operationLog = new OperationLog();
                                operationLog.setAdmin(admin.getName());
                                operationLog.setOperation(property);
                                operationLog.setCreateBy(adminId);
                                operationLog.setUpdateBy(adminId);
                                logs.add(operationLog);
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        }
                    }
                });
            }
            //及时关闭,否则可能引起内存泄露
            threadPoolExecutor.shutdown();
            if (logs.size() != 0) {
                try {
                    //批量插入
                    operationLogService.insertList(logs);
                    log.info("==================insert database finish>>");
                    logs.clear();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    @Scheduled(cron = "0 0 0/1 * * ?")
    public void timer() {
        //spring timer定时提交任务
        commitLogPool();
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值