双缓冲机制是在hadoop刷写元数据的时候进行的操作。
模仿hadoop刷写的过程编写简易的双缓冲代码。
import java.util.LinkedList;
import java.util.concurrent.atomic.LongAdder;
public class FSEditlog {
public class Editlog {
private long txid;//事务ID
private String log;//日志
public Editlog(long txid, String log) {
this.txid = txid;
this.log = log;
}
@Override
public String toString() {
return "Editlog{" +
"txid=" + txid +
", log='" + log + '\'' +
'}';
}
}
public class DoubleBuf {
//第一块内存 bufCurrent
LinkedList<Editlog> bufCurrent = new LinkedList<Editlog>();
//第二块内存 bufReady
LinkedList<Editlog> bufReady = new LinkedList<Editlog>();
//写入内存操作
public void write(Editlog editlog) {
bufCurrent.add(editlog);
}
//写磁盘,元数据持久化
public void flush() {
for (Editlog editlog : bufReady) {
System.out.println("当前线程ID: " + Thread.currentThread().getId() + " 当前元数据刷到磁盘:" + editlog);
}
//刷完盘之后,清空内存
bufReady.clear();
}
//交换内存
public void setReadyToFlush() {
LinkedList<Editlog> temp = bufCurrent;
bufCurrent = bufReady;
bufReady = temp;
}
//获取最大事务ID
public long getMaxTxid() {
return bufReady.getLast().txid;
}
}
//记录事务id
LongAdder txid = new LongAdder();
DoubleBuf doubleBuf = new DoubleBuf();
ThreadLocal<Long> threadLocal = new ThreadLocal<Long>();
public void writeEditlog(String log) {
synchronized (this) {
txid.increment(); // 1 2 3 4
threadLocal.set(txid.longValue());
final Editlog editlog = new Editlog(txid.longValue(), log);
doubleBuf.write(editlog);
}
//持久化元数据
logSync();
}
//是否正在同步刷盘的标志位
public boolean isSyncRunning = false;
//记录最大事务ID , 以后只操作最大的事务iD
long syncStart = 0;
//是否线程等待标志位
boolean isWait = false;
//刷盘操作
public void logSync() {
//锁开始
synchronized (this) {
//有线程正在刷盘
if (isSyncRunning) {
//如果当前线程id < 最大事务id,意味着当前线程工作已经被其他线程完成了
//说明当前线程任务已经被其他线程处理完毕了,所以什么也不用做
if (threadLocal.get() < syncStart) {
return;
}
if (isWait) {
return;
}
isWait = true;
while (isSyncRunning) { //线程2 进来了,发现线程1处于isSyncRunning , 线程2等待
try {
this.wait(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//此时刷盘结束,不需要等待了
isWait = true;
}
//交换内存
doubleBuf.setReadyToFlush();
//更新获取最大事务Id
if (doubleBuf.bufReady.size() > 0) {
syncStart = doubleBuf.getMaxTxid();
}
//交换内存之后,具备了刷盘条件
isSyncRunning = true;
}//锁结束
doubleBuf.flush();
//刷完
synchronized (this) {
isSyncRunning = false;
this.notifyAll();
}
}
public static void main(String[] args) {
final FSEditlog fsEditlog = new FSEditlog();
boolean isRunning = true;
long txid = 0;
while (isRunning) {
txid++;
if (txid == 100) {
isRunning = false;
}
new Thread(new Runnable() {
boolean isRunning = true;
long txid = 0;
@Override
public void run() {
while (isRunning) {
txid++;
if (txid == 100) {
isRunning = false;
}
fsEditlog.writeEditlog("元数据");
}
}
}).start();
}
}
}
运行结果如下: