一、概述

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

最简单的做法是,封装一个公共的写日志的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. U3D navmesh寻路简单示范

    要求:放置一个BOSS,创建几个路标,自动循环这几个路标形成回路,变成自动巡逻,并配合animator系统的控制开关控制BOSS的动作 1.先设置好BOSS 中animator的控制开关,只看Run和 ...

  2. FFTW程序Demo

    #include<stdio.h> #include<stdlib.h> #include <fftw3.h> #include<string.h> # ...

  3. Error D8016 '/ZI' and '/Gy-' command-line options are incompatible

    使用vs运行工程时出现错误: Severity Code Description Project File Line Suppression StateError D8016 '/ZI' and '/ ...

  4. 杭电ACM 2052 Picture

    Picture Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Su ...

  5. uoj #2 【NOI2014】起床困难综合症 贪心+位运算

    题目链接 给出n个数, 每个数有特定的一种操作, &|^三种, 给出一个m, 初始值属于[0,m],选定一个初始值, 使所有操作做完之后的值最大, 输出这个最大值. 1, 从最高位贪心, 如果 ...

  6. poj 2356

    http://poj.org/problem?id=2356 方法一:  鸽巢原理 解题思路:  n个数,,依次求其s[0],s[1],s[2],s[3].....s[n]  然后对 n取模,,必然会 ...

  7. MVC3 Html.ActionLink

    以下使用参数文字说明: linkText:生成的链接所显示的文字   类型:string actionName:对应控制器的方法 类型:string routeValues:向对应的action传递的 ...

  8. 如何优化你的JS脚本来减少reflow/repaint?

    如何优化你的脚本来减少reflow/repaint?1. 避免在document上直接进行频繁的DOM操作,如果确实需要可以采用off-document的方式进行,具体的方法包括但不完全包括以下几种: ...

  9. Qt Installer Framework的学习

    Qt Installer Framework是Qt默认包的发布框架.它很方便,使用静态编译Qt制作而成.并且使用了压缩率很高的7z对组件进行压缩.之所以有这些好处,我才觉得值得花一点儿精力研究一下这个 ...

  10. 《Clean Code》重点内容总结

    读书笔记请见Github博客:http://wuxichen.github.io/Myblog/reading/2014/10/06/CleanCode.html