大并发操作数据库, 多次插入比较耗费资源, 故使用生产者-消费者模型做了这个工具
实现功能
1.队列中缓存MAX_TASK_COUNT个任务, 如果超过这个数目, 开始批量工作, 如插入到数据库
2.队列中如果一直没有放入任务, 在FORCE_WORK_TIME时间之后会强制执行一次
3.在线程退出的时候会尽量将剩下的任务执行完
package com.su.iot.server.db.cache;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import com.su.iot.server.util.LogUtil;
/**
* Assistant of database transaction. Matin a Queue and insert to database if
* the task arrive MAX_TASK_COUNT
*/
public class DBTransactionTask implements Runnable
{
private static final DBTransactionTask inst = new DBTransactionTask();
private static final int MAX_TASK_COUNT = 3;
private static final int FORCE_WORK_TIME = 5 * 1000; //force work time
private Thread mThread = null;
private final LinkedList<Work> mWorkQueue = new LinkedList<Work>();
private long mLastSaveTime = 0;
public static DBTransactionTask i() {
return inst;
}
@Override
public void run() {
mLastSaveTime = System.currentTimeMillis();
ArrayList<Work> workList = new ArrayList<Work>();
while (true) {
boolean interrupted = false;
synchronized (mWorkQueue) {
long waitTime = 0;
while (true) {
// task enough , break
if (mWorkQueue.size() >= MAX_TASK_COUNT) {
break;
}
//force work time arrive, and works exists, break.
if ((mWorkQueue.size() > 0 && (waitTime = FORCE_WORK_TIME - (System.currentTimeMillis() - mLastSaveTime)) < 0)) {
break;
}
try {
mWorkQueue.wait(waitTime);
}
catch (InterruptedException e) {
LogUtil.e("interrupted!");
e.printStackTrace();
interrupted = true;
break;
}
}
workList.addAll(mWorkQueue);
LogUtil.e("mWorkQueue clear :" + mWorkQueue.size());
mWorkQueue.clear();
}
if (!interrupted) {
if (workList.size() > 0) {
// start transtraction work!
startTransaction(workList);
int ok = 0;
if (ok == 0) {
workList.clear(); //继续下一轮的work收集
}
}
mLastSaveTime = System.currentTimeMillis();
}
else {
LogUtil.d("Thread was interrupted, finishing the last tasks");
// 如果interrupted了,则尝试将没有写入数据库的数据写进去
if (mWorkQueue.size() > 0) {
try {
// start transtraction work!
startTransaction(mWorkQueue);
}
catch (Exception e) {
LogUtil.e("save statistic data to db error,");
e.printStackTrace();
}
}
}
}
}
public void add(final Work work) {
LogUtil.d("adding work " + work + " mWorkQueue size" + mWorkQueue.size());
synchronized (mWorkQueue) {
mWorkQueue.addLast(work);
mWorkQueue.notify();
}
}
public synchronized void start() {
if (mThread != null) {
LogUtil.d("DBTransactionTask already started!");
return;
}
mThread = new Thread(this, "DBTransactionTask");
// mThread.setDaemon(true);
mThread.start();
LogUtil.d("DBTransactionTask start");
}
public synchronized void stop() {
if (mThread != null) {
mThread.interrupt();
}
else {
LogUtil.d("DBTransactionTask already stopped!");
}
mThread = null;
}
public boolean startTransaction(List<Work> work) {
LogUtil.d("startTransaction----------------------------------");
for (int i = 0; i < work.size(); i++) {
Work work2 = work.get(i);
if (work2 == null) {
LogUtil.e("work is null !!");
}
else {
work2.doWork();
}
}
// try {
// JDBCUtil.i().beginTransaction();
// for (int i = 0; i < work.size(); i++) {
// Work work2 = work.get(i);
// if (work2 == null) {
// LogUtil.e("work is null !!");
// }
// else {
// work2.doWork();
// }
// }
// JDBCUtil.i().commit();
// JDBCUtil.i().endTransaction();
// return true;
// }
// catch (Exception e) {
// JDBCUtil.i().roolback();
// JDBCUtil.i().endTransaction();
// e.printStackTrace();
//
// }
LogUtil.d("endTransaction----------------------------------");
return false;
}
public abstract static class Work
{
private String id;
public Work setId(String id) {
this.id = id;
return this;
}
public String getId() {
return id;
}
public abstract void doWork();
}
public static void main(String[] args) {
DBTransactionTask.i().start();
for (int i = 0; i < 5; i++) {
final int taskid = i;
Work work = new Work()
{
@Override
public void doWork() {
LogUtil.d("I am running " + taskid);
try {
Thread.sleep(1000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
};
DBTransactionTask.i().add(work);
}
}
}