ConcurrentLinkedQueue实现异步日志写入

北战南征 提交于 2019-11-25 23:54:23

        在用户操作量较大的情况下,如果实时写入日志会导致资源被严重占用,用户长时间获取不到返回结果,影响用户体验,所以日志操作通常是在用户操作完后放入异步队列,等用户操作少的时间段再将日志写入数据库。

        此处实现异步日志写入用到了并发包下的ConcurrentLinkedQueue,一个线程安全的队列实现,遵循FIFO原则进行排序,采用CAS操作,来保证元素的一致性。

        首先采用模板模式,定义一个异步队列服务的模板类BaseAsyncQueueService,其中包含一个队列log_queue,和异步操作的抽象方法asyncProcess()。

/**
 * 基础异步队列服务,用于异步保存日志信息
 */
public abstract class BaseAsyncQueueService<T> {

  /**
   * 处理,消费
   * @param t
   * @return
   */
  public abstract boolean asyncProcess(T t);

  /**
   * 队列
   */
  private ConcurrentLinkedQueue<Object> log_queue;

  public BaseAsyncQueueService() {
    log_queue = new ConcurrentLinkedQueue();
  }

  public synchronized boolean isEmpty() {
    return log_queue.isEmpty();
  }

  public synchronized int getSize() {
    return log_queue.size();
  }

  public synchronized T poll() {
    return (T) log_queue.poll();
  }

  public synchronized void offer(T bean) {
    log_queue.offer(bean);
  }
}

然后需要异步写入日志的Service只需要继承模板类,并实现asyncProcess()即可

@Service
public class UserService extends BaseAsyncQueueService<User>{

  @Override
  public boolean asyncProc(User user) {
    if(null == user)
      return false;
    try {
      UserLog userLog = new UserLog();
      userLog.setUserId(user.getId());
      LogService.save(UserLog);
      return true;
    }catch (Exception e){
      log.warn("异步写入日志失败!!!", e);
    }
    return false;
  }

}

然后通过一个统一任务类去触发各个Service中的异步写入任务,这里用到了@PostConstruct注解,即在被注入的UserService实例化时就调用


/**
 * 异步消费处理task
 */
public abstract class BaseAsyncQueueThreadTask {

  private static final Log log = LogFactory.getLog(BaseAsyncQueueThreadTask.class);

  /**
   * 是否处理
   *
   * @return
   */
  protected abstract boolean isProc();

  protected abstract BaseAsyncQueueService getAsyncQueueService();

  public int getSize(){
    return this.getAsyncQueueService().getSize();
  }

  /**
   * 开启线程数量
   *
   * @return
   */
  public int getThreadNum() {
    return 1;
  }

  @PostConstruct
  public void task() {
    for (int i = 0; i < getThreadNum(); i++) {
      new TaskThread().start();
    }
  }

  class TaskThread extends Thread {

    @Override
    public void run() {
      while (true) {
        try {
          Object bean = getAsyncQueueService().poll();
          if (!isProc())
            return;
          if (bean == null) {
            // 如果是空,则休息2秒
            ThreadUtil.sleepSeccond(2);
          } else {
            boolean rest = getAsyncQueueService().asyncProc(bean);
            if (rest)
              addSuccessCount();
            else
              addErrorCount();
          }
        } catch (Exception e) {
          log.error(e, e);
          addErrorCount();
        }
      }
    }

  }

}

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!