欢迎使用CSDN-markdown编辑器

来源:互联网 发布:淘宝客为什么要用软件 编辑:程序博客网 时间:2024/06/01 19:34

JAVA 异步编程总结和异步编程资源回收问题(多线程)

最近在公司写日志系统发现一个很诡异的Bug,经过排查是异步编程资源回收问题没有处理的好的问题,故再次记录一下,方便以后自己复习,和让别人新手少走弯路。

  • *什么情况要异步编程
    高并发场景,某个任务占据线程的时间过长,或者对性能没有要求,对准确性有要求的场景。
    我举个例子:
    1.备份文件,假设我要要备份一个磁盘下的所有文件,这个时候某个文件内容过大,会占据线程的时间过长,那这个时候就可以起多个线程去进行备份。
    2.最近做的日志业务,做日志的目的是为了更好的让运营平台去风控,但是不能为了记录日志影响了主业务的反应时间,这样会影响用户体验,这时候我们也可以进行多线程编程,将日志任务放到其他线程中去运行。
    3.高并发场景。

异步资源回收问题

直接上代码,仔细的同学会发现里面有一个Bug吗?我会加粗

//最近写的日志项目代码,发送日志服务//接口定义public void sendBusinessLog(Map<String,Object> params);businessLogService.sendBusinessLog(CollectionUtil.hashMap(                    BusinessLogUtil.LOG_PARAM_CHANGE_BEFORE, null,                    BusinessLogUtil.LOG_PARAM_CHANGE_AFTER, terminal_activation_codeNew,                   //此处传入HttpRequest                    BusinessLogUtil.LOG_PARAM_REQUEST, **HttpRequestUtil.getRequest(),                    BusinessLogUtil.LOG_PARAM_OP_PARAMS, CollectionUtil.hashMap(                            BizOpLog.BUSINESS_OBJECT_CODE, "terminal",                            BizOpLog.OP_TYPE, BizOpLog.OP_TYPE_ADD,                            BusinessLogUtil.LOG_PARAM_OP_PARAMS_TABLENAME, "terminal_activation_code",                            BusinessLogUtil.LOG_PARAM_OP_PARAMS_OBJECT_ID, "merchant_id"                    )            ));
上完整接口代码@Override    public void enableVendor(Map<String, Object> request) {        String vendorId = BeanUtil.getPropString(request, ConstantUtil.KEY_ID);        Map vendorOld = vendorService.getVendor(vendorId);        vendorService.enableVendor(vendorId);        Map vendorNew = vendorService.getVendor(vendorId);        //发送日志,此处后台做多线程处理        businessLogService.sendBusinessLog(CollectionUtil.hashMap(                BusinessLogUtil.LOG_PARAM_CHANGE_BEFORE,vendorOld,                BusinessLogUtil.LOG_PARAM_CHANGE_AFTER,vendorNew,                BusinessLogUtil.LOG_PARAM_REQUEST, HttpRequestUtil.getRequest(),                BusinessLogUtil.LOG_PARAM_OP_PARAMS,CollectionUtil.hashMap(                        BizOpLog.BUSINESS_OBJECT_CODE,"vendor",                        BizOpLog.OP_TYPE,BizOpLog.OP_TYPE_MODIFY,                        BusinessLogUtil.LOG_PARAM_OP_PARAMS_TABLENAME,"vendor",                        BusinessLogUtil.LOG_PARAM_OP_PARAMS_OBJECT_ID,DaoConstants.ID                )        ));        //无返回值    }

实际应用中我们发现,改日志记录过程会有的会记录,有的不会记录,尤其当项目刚刚构建的时候,必不会记录。经过排查逻辑代码无Bug,这就很奇怪了,为什么会发生这样的事情呢?

通过Loginfo,我发现只要当一跳请求被发送到接口出与日志记录系统打印参数信息的时间超过60毫秒,日志就不会记录。

为什么?

//此处传入HttpRequestBusinessLogUtil.LOG_PARAM_REQUEST, **HttpRequestUtil.getRequest()

我们这里传入的一个request的地址,由于日志发送是异步的,所以当日志还未处理到获取Http头部的具体信息的收就已经返回了,也就是说BusinessLogUtil.LOG_PARAM_REQUEST这个参数此时已经为空,这也就是问什么日志无法记录了。

总结
*异步编程时要考虑到当*A线程函数返回时,你的其他的线程中是否使用了**A线程中得资源。

原创粉丝点击