业务场景:
实时写hbase,但是每次写hbase都需要数据的传输和提交,所以希望可以改成批量写入。
这里有两个需求:
为了避免一次性写入很多,所以需要做上限的校验。
1.定时批量写入(即每个一段时间写入);
2.定量批量写入(即超过一定数量上限后写入);
优化后的代码如下(删除了一些不需要的代码):
这里用到了
ReentrantLock和
Condition,Condition的逻辑其实类似于同步关键字里面对象锁,await
()
相当于wait
()
,signal
()
相当于notify();
同样,这两个函数的前提是获取锁,
signal
()只是标记一下释放的状态,真正的释放需要等待
await
()和unlock()函数才会触发。
class HbaseBatchSaveExecutor
extends
Thread
implements Serializable {
/**
* 等待锁
*/
ReentrantLock wait = new ReentrantLock();
Condition overLimit = wait.newCondition();
/**
* 间隔时间
*/
private long intervalTime = 0;
private int overLimitNum = 0;
volatile int
perCycleNum
=
0
;
/**
*
* @param overLimitNum 存储的数量上限,超过这个数 可以进行数据存储了 默认500条
* @param intervalTime 超时上限,超过这个时间 也可以进行数据存储了 默认1000ms
*/
public HbaseBatchSaveExecutor(Integer overLimitNum, Long intervalTime){
if(intervalTime == null){
this.intervalTime = 1000L;
}else{
this.intervalTime = intervalTime;
}
if(overLimitNum == null){
this.overLimitNum = 500;
}else{
this.overLimitNum = overLimitNum;
}
}
public boolean add(...){
try {
...
//数量累加,超过上限时通知取消等待
if(perCycleNum++ > overLimitNum){
signalOverLimit();
}
return true;
}catch (Exception e){
//打印日志
return false;
}
}
@Override
public void run() {
while(true){
lockAndWait();
//做其他事情
}
}
/**
* 锁并等待
*/
private void lockAndWait() {
try{
wait.lockInterruptibly();
//获取锁,并进入等待 释放锁
overLimit.await(intervalTime, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
//异常捕获
} finally {
//这里一定要释放锁
wait.unlock();
}
}
private void signalOverLimit() {
//和同步关键字一样,如果需要发送信号,需要先获取锁
wait.lock();
try {
//发送信号
overLimit.signal();
} finally {
//这里才会真正的通知 之前await()的线程
wait.unlock();
}
}
//其他一些代码...
}