利用java concurrent 包实现日志写数据库的并发处理
一、概述
在很多系统中,往往需要将各种操作写入数据库(比如客户端发起的操作)。
最简单的做法是,封装一个公共的写日志的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 包实现日志写数据库的并发处理的更多相关文章
- java concurrent包的学习(转)
java concurrent包的学习(转) http://my.oschina.net/adwangxiao/blog/110188 我们都知道,在JDK1.5之前,Java中要进行业务并发时,通常 ...
- Java网络编程:利用Java mail包发送电子邮件
下面代码是利用Java mail包封装了一个发送邮件的类 import java.io.File; import java.util.ArrayList; import java.util.Date; ...
- java Concurrent包学习笔记(四):BlockingQueue
一.BlockingQueue概述 1.阻塞的含义 BlockingQueue即阻塞队列,从阻塞这个词可以看出,在某些情况下对阻塞队列的访问可能会造成阻塞.被阻塞的情况主要有如下两种: ,当一个线程对 ...
- java concurrent包的实现原理
由于java的CAS同时具有 volatile 读和volatile写的内存语义,因此Java线程之间的通信现在有了下面四种方式: A线程写volatile变量,随后B线程读这个volatil ...
- java Concurrent包学习笔记(一):ExecutorService
一.介绍 ExecutorService是java.util.concurrent包中的一个线程池实现接口.其有两个实现类: 1)ThreadPoolExecutor:普通线程池通过配置线程池大小,能 ...
- 利用“Java同包同名类执行顺序”取消Java 网站应用程序Licence验证
如果是在tomcat里运行,lib目录下一大堆的JAR包,不同的JAR包里可能会有相同的包名类名,JRE按照JAR名字的字母顺序加载JAR文件,同名类如果已加载,则后面的同名类会忽略. 公司购买的一款 ...
- java Concurrent包学习笔记(六):Exchanger
一.概述 Exchanger 是一个用于线程间协作的工具类,Exchanger用于进行线程间的数据交换,它提供一个同步点,在这个同步点,两个线程可以交换彼此的数据.这两个线程通过exchange 方法 ...
- java Concurrent包学习笔记(五):Semaphore
一.Semaphore 是什么 信号量Semaphore是一个并发工具类,用来控制可同时并发的线程数,其内部维护了一组虚拟许可,构造函数初始化的时候可以指定许可的总数量 每次线程执行操作时先通过ac ...
- java Concurrent包学习笔记(三):ReentrantLock
一.可重入性的理解 从名字上理解,ReenTrantLock的字面意思就是再进入的锁,其实synchronized关键字所使用的锁也是可重入的,两者关于这个的区别不大.两者都是同一个线程每进入一次,锁 ...
随机推荐
- MySQl 存储过程+游标
DROP PROCEDURE IF exists pro_Insertflightplan_stat; create procedure pro_Insertflightplan_stat(exec ...
- 【Linux命令】mysql数据库常用操作命令
#数据库操作: #建立数据库 create database data_name #删除数据库 drop database data_name #查看: show databases; #表操作: # ...
- hadoop序列化机制与java序列化机制对比
1.采用的方法: java序列化机制采用的ObjectOutputStream 对象上调用writeObject() 方法: Hadoop 序列化机制调用对象的write() 方法,带一个DataOu ...
- JS常用方法函数(1)
1.字符串长度截取 function cutstr(str, len) { var temp, icount = 0, patrn = /[^\x00-\xff]/, strre = "&q ...
- net core 静态文件
asp.net core 之静态文件目录的操作 文章前言 之前写了一篇关于模拟登录的文章,自我感觉内容不太丰富,今天的这篇文章,希望在内容上能丰富些.本人缺少写文章的经验,技术上也是新手,但我会努 ...
- 如何优化你的JS脚本来减少reflow/repaint?
如何优化你的脚本来减少reflow/repaint?1. 避免在document上直接进行频繁的DOM操作,如果确实需要可以采用off-document的方式进行,具体的方法包括但不完全包括以下几种: ...
- 通过Qt样式表定制程序外观(比较通俗易懂)
1. 何为Qt样式表[喝小酒的网摘]http://blog.hehehehehe.cn/a/10270.htm2. 样式表语法基础3. 方箱模型4. 前景与背景5. 创建可缩放样式6. 控制大小7. ...
- vs2010 条件断点 has changed是什么意思?
在vs2010 断点设置 condition里,有2个选项可以选择: 一个是true,另个是has changed,true好理解,如果表达式为真则停止.但是has changed是什么意思.看了官网 ...
- 从零开始学C++之IO流类库(三):文件的读写、二进制文件的读写、文件随机读写
一.文件的读写 如前面所提,流的读写主要有<<, >>, get, put, read, write 等操作,ofstream 继承自ostream, ifstream 继承自 ...
- Parrot源代码分析之海贼王
我们的目的是找到speedup-example在使用Parrot加速的原因,假设仅仅说它源于Context Switch的降低,有点简单了,它究竟为什么降低了?除了Context Switch外是否还 ...