栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java 使用双内存缓冲区 实现简易日志组件

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java 使用双内存缓冲区 实现简易日志组件

在实现简易日志组件时,为了写日志的同时,可将日志数据进行写入磁盘实现持久化。如果每记录一条日志就写一次磁盘文件的话, 磁盘IO会占用正常处理逻辑的性能。因此,采用双内存缓冲区的思路来将写日志与写磁盘文件这两个动作进行解耦。

1、将业务日志写入到日志缓冲区
2、当进行刷盘时,将日志缓冲区的数据转移到待刷盘缓冲区
3、日志缓冲区继续执行,而刷盘线程可另外工作

以下为实现的逻辑代码:

package com.dfs.namenode.server;

import java.util.linkedList;


public class FSEditLog {

    
    private long txidSeq = 0L;

    
    private ThreadLocal localTxid = new ThreadLocal<>();

    
    private DoubleBuffer editLogBuffer = new DoubleBuffer();

    
    private boolean isSyncRunning = false;

    
    private long syncMaxTxid = 0;

    
    private boolean isWaitSync;

    
    public void LogEdit(String content) {
        //上锁写buffer
        synchronized (this) {
            //每次写日志都递增一次日志序号
            txidSeq++;
            long txid = txidSeq;
            //将日志序号写到当前线程栈
            localTxid.set(txid);

            EditLog log = new EditLog(txid, content);

            editLogBuffer.Write(log);
        }
        //将内存缓存的日志写入磁盘文件
        logSync();
    }

    
    private void logSync() {
        synchronized (this) {
            if(isSyncRunning) {
                //当前写线程的日志序号
                long txid = localTxid.get();
                //已刷盘的序号已经大于当前id,说明已被其他线程刷盘了
                if (txid <= syncMaxTxid) {
                    return;
                }
                //有线程正在等待刷新磁盘
                if(isWaitSync) {
                    return;
                }
                //进行刷盘
                isWaitSync = true;
                while(isSyncRunning) {
                    try {
                        wait(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                isWaitSync = false;
            }
            //交换两块缓存去
            editLogBuffer.SetReadyToSync();
            //获取已刷盘的日志最大序号
            syncMaxTxid = editLogBuffer.GetSyncMaxTxid();
            isSyncRunning = true;
        }
        //将缓存数据写入磁盘文件
        editLogBuffer.Flush();

        synchronized (this) {
            //将标志位复位再释放锁
            isSyncRunning = false;
            //唤醒可能正在等待同步刷盘的线程
            notifyAll();
        }
    }

    class EditLog {
        private long txid;

        private String content;

        public EditLog(long txid, String content) {
            this.txid = txid;
            this.content = content;
        }
    }

    class DoubleBuffer {
        
        linkedList currentBuffer = new linkedList<>();

        
        linkedList syncBuffer = new linkedList<>();

        public void Write(EditLog log) {
            currentBuffer.add(log);
        }

        
        public void SetReadyToSync() {
            linkedList tmp = currentBuffer;
            currentBuffer = syncBuffer;
            syncBuffer = tmp;
        }

        
        public long GetSyncMaxTxid() {
            return syncBuffer.getLast().txid;
        }

        
        public void Flush() {
            for(EditLog log : syncBuffer) {
                //用文件输出流将数据写入磁盘文件中
            }
            syncBuffer.clear();
        }
    }
}

在java nio中也实现了DoubleBuffer这个类,感兴趣的朋友也可以看看

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/397456.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号