一、概述

在很多系统中,往往需要将各种操作写入数据库(比如客户端发起的操作)。

最简单的做法是,封装一个公共的写日志的api,各个操作中调用该api完成自己操作日志的入库。但因为入数据库效率比较低,如果每个操作自己入库,则会影响响应速度。而且当操作并发度很高时,往往同时有多个线程在写数据库,也会对系统有影响。

考虑的解决方案是,这个api并不实际完成入库,而是将每个操作日志信息写到一个公共的缓存中,然后应用系统起了一个独立的线程(一直运行)在后台进行入库。如果当前缓存中有记录,就写库,没有记录,就堵塞住。

这里关键的是要有一个缓存日志的数据结构,我们这里使用java current包中的并发数据结构LinkedBlockingDeque类。

二、具体代码

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.LinkedBlockingDeque; public class LogManager implements Runnable {
//定义缓存数据结构,支持并发操作
private static LinkedBlockingDeque<ActionLog> list = new LinkedBlockingDeque<ActionLog>();
static{
//创建并启动线程,该线程实现日志的入库
new Thread(new LogManager()).start();
}
public static void addActionLog(ActionLog log) {
list.add(log);
} @Override
public void run() {
List<ActionLog> items = new ArrayList<ActionLog>();
while (true) {
//从缓存中取出1条日志,但不从缓存中删除。用于检查队列中是否有数据
ActionLog item = list.peek();
if (item == null && items.size() > 0) {
//item为null说明缓存中没有日志了,这时如果临时队列items中有记录,就可以批量入库了
work(items);
}
//从缓存中取出并删除最前面的日志,如果无数据,在堵塞
ActionLog result = deleteItem();
//将取出的记录放到临时队列中
items.add(result);
}
} private ActionLog deleteItem() {
ActionLog result = null;
try {
//取出并删除最前面的一条数据,如果缓存中无数据,则堵塞住
result = list.takeFirst();
} catch (InterruptedException e) {
e.printStackTrace();
}
return result;
} private void work(List<ActionLog> items) {
//TODO 完成入库。这里代码没有提供
//入库后删除临时队列中记录
items.clear();
} }

各种工作线程调用 addActionLog 方法将要入库的日志放到缓存中。由LogManager通过自己的线程控制入库。

三、小结

上述代码虽然简单,但很好的解决了前面提出的问题。不过这个解决方案存在一个问题。

如果说系统产生日志的速度超过了单个线程入库的速度,上述代码就有问题。就会造成该线程不停地入库。

这时就需要考虑增加额外的处理速度,如增加入库线程。

所以上述代码,只适合并发日志量不是特别大的情况下的场景。

利用java concurrent 包实现日志写数据库的并发处理的更多相关文章

  1. java concurrent包的学习(转)

    java concurrent包的学习(转) http://my.oschina.net/adwangxiao/blog/110188 我们都知道,在JDK1.5之前,Java中要进行业务并发时,通常 ...

  2. Java网络编程:利用Java mail包发送电子邮件

    下面代码是利用Java mail包封装了一个发送邮件的类 import java.io.File; import java.util.ArrayList; import java.util.Date; ...

  3. java Concurrent包学习笔记(四):BlockingQueue

    一.BlockingQueue概述 1.阻塞的含义 BlockingQueue即阻塞队列,从阻塞这个词可以看出,在某些情况下对阻塞队列的访问可能会造成阻塞.被阻塞的情况主要有如下两种: ,当一个线程对 ...

  4. java concurrent包的实现原理

      由于java的CAS同时具有 volatile 读和volatile写的内存语义,因此Java线程之间的通信现在有了下面四种方式:   A线程写volatile变量,随后B线程读这个volatil ...

  5. java Concurrent包学习笔记(一):ExecutorService

    一.介绍 ExecutorService是java.util.concurrent包中的一个线程池实现接口.其有两个实现类: 1)ThreadPoolExecutor:普通线程池通过配置线程池大小,能 ...

  6. 利用“Java同包同名类执行顺序”取消Java 网站应用程序Licence验证

    如果是在tomcat里运行,lib目录下一大堆的JAR包,不同的JAR包里可能会有相同的包名类名,JRE按照JAR名字的字母顺序加载JAR文件,同名类如果已加载,则后面的同名类会忽略. 公司购买的一款 ...

  7. java Concurrent包学习笔记(六):Exchanger

    一.概述 Exchanger 是一个用于线程间协作的工具类,Exchanger用于进行线程间的数据交换,它提供一个同步点,在这个同步点,两个线程可以交换彼此的数据.这两个线程通过exchange 方法 ...

  8. java Concurrent包学习笔记(五):Semaphore

    一.Semaphore 是什么  信号量Semaphore是一个并发工具类,用来控制可同时并发的线程数,其内部维护了一组虚拟许可,构造函数初始化的时候可以指定许可的总数量 每次线程执行操作时先通过ac ...

  9. java Concurrent包学习笔记(三):ReentrantLock

    一.可重入性的理解 从名字上理解,ReenTrantLock的字面意思就是再进入的锁,其实synchronized关键字所使用的锁也是可重入的,两者关于这个的区别不大.两者都是同一个线程每进入一次,锁 ...

随机推荐

  1. PeopleEditor的取值及赋值

    /// <summary> /// 从PeopleEditor取值 /// </summary> /// <param name="peopleEditor&q ...

  2. 【转】CTE(公用表表达式)

    本文转自:爽朗的微笑  http://www.cnblogs.com/shuangnet/archive/2013/03/22/2975929.html 公用表表达式 (CTE) 具有一个重要的优点, ...

  3. MD5校验及其c实现

    那么MD5校验是什么? 一般软件或者说文件都有自己的固定文件格式或者架构信息,说简单一点就是.”世界上没有完全相同的2片叶子” ,因为MD5是一种不可逆的加密算法. 那么对于某些网上公开下载的软件,视 ...

  4. 控制台console使用MFC库函数,Cout输出CString的方法

    新建工程的时候选择:Win32 Console Application 在向导的地方勾选MFC头文件支持,确认即可 等待初始化文件完成后,VS2010会自动打开 项目名.cpp的文件 其中int _t ...

  5. fieldset效果

    <form> <fieldset> <legend>健康信息</legend> 身高:<input type="text" / ...

  6. python成长之路10

    断点续传   python2.7 多继承  py35多继承   socketserver源码     支持并发处理socket   i/o多路复用   上节回顾     socket          ...

  7. css基本框架

  8. extjs 优化小建议

    1 原文信息 原文标题: Sencha Con 2013: Ext JS Performance tips 原文地址: [http://edspencer.net/2013/07/19/sencha- ...

  9. 在CTime类中重载&lt;&lt;和&gt;&gt;

    程序代码: #include <iostream> using namespace std; class CTime//时间类 { private: unsigned short int ...

  10. C++创建动态链接库(*.dll)

    1.      从 “文件”菜单中,选择 “新建”,然后选择 “项目…”. 2.      在“项目类型”窗格中,选择“Visual C++”下的“Win32”. 3.      在“模板”窗格中,选 ...