java使用双内存缓冲区实现简易日志组件(代码片段)

BBinChina BBinChina     2023-01-23     402

关键词:

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

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

以下为实现的逻辑代码:

package com.dfs.namenode.server;

import java.util.LinkedList;

/**
 * 文件变更日志
 */
public class FSEditLog 

    /**
     * 日志序号
     */
    private long txidSeq = 0L;

    /**
     * 用于存储当前写线程的日志序号
     */
    private ThreadLocal<Long> localTxid = new ThreadLocal<>();

    /**
     * 双层缓存,用于写日志,同时可刷盘
     */
    private DoubleBuffer editLogBuffer = new DoubleBuffer();

    /**
     * 默认没人在刷盘
     */
    private boolean isSyncRunning = false;

    /**
     * 已刷盘的最大日志序号
     */
    private long syncMaxTxid = 0;

    /**
     * 是否有线程在等待刷新下一批log到磁盘文件
     */
    private boolean isWaitSync;

    /**
     * 记录log日志
     * @param content
     */
    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 
        /**
         * 用来缓存写入的log
         */
        LinkedList<EditLog> currentBuffer = new LinkedList<>();

        /**
         * 用来将日志进行刷盘
         */
        LinkedList<EditLog> syncBuffer = new LinkedList<>();

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

        /**
         * 将写入的日志缓存数据转到待刷盘的缓存列表中
         */
        public void SetReadyToSync() 
            LinkedList<EditLog> tmp = currentBuffer;
            currentBuffer = syncBuffer;
            syncBuffer = tmp;
        

        /**
         * @return 已记录的日志序号
         */
        public long GetSyncMaxTxid() 
            return syncBuffer.getLast().txid;
        

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


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

使用fileupload实现文件上传(代码片段)

...skFileItemFactory(intsizeThreshold,Filerepository)  sizeThreshold内存缓冲区,不能设置太大,否则会导致JVM崩溃  reposi 查看详情

华为od机试真题java实现简易内存池2真题+解题思路+代码(2022&2023)(代码片段)

简易内存池2题目请实现一个简易内存池根据请求命令完成内存分配和释放内存池支持两种操作命令REQUEST和RELEASE其格式为REQUEST=请求的内存大小表示请求分配指定大小内存如果分配成功,返回分配到的内存首地址如果内存不足,... 查看详情

qt的简易日志库实现及封装(代码片段)

...用于记录日志到文件够用了。单独的一个文件模块,使用时直接引入源码。想要其他功能,直接改代码即可。C++的下的日志库有很多,如log4cpp、Easylogging++,eplog,g3log,Qt下也有log4qt。还有 查看详情

javalogback简易教程(代码片段)

本作品采用知识共享署名-非商业性使用4.0国际许可协议进行许可。一、前言本文以一个简单的项目为例,一步步展示logback的同步和异步配置方法,并且配置的日志要求满足阿里巴巴Java开发手册-日志规约,因为对于... 查看详情

vue实现一个简易popover组件(代码片段)

...组件,非常不灵活。最近看museUI库,发现它的下拉框Select实现的非常灵活,点击组件外也能控制下拉框关闭,于是想探究一番, 查看详情

postgresql体系架构(代码片段)

...f0c;会生成一块共享内存,共享内存主要用作数据块的缓冲区,以便提高读写性能。WAL日志缓冲区和CLOG(Commitlog)缓冲区也存在于共享内存中。除此之外,一些全局信息也保存在共享内存中,如进程信息、... 查看详情

android简易音乐重构mvvmjava版-使用navigation导航组件重构主界面及其他页面跳转(二十)(代码片段)

Android简易音乐重构MVVMJava版-使用Navigation导航组件重构主界面及其他页面跳转(二十)关于效果图实现修改Activity_main.xml页面修改MainActivity.java新建一个libCommon的library(一些kotlin写的工具放在这里)修改nav_graph.xml... 查看详情

android简易音乐重构mvvmjava版-使用navigation导航组件重构主界面及其他页面跳转(二十)(代码片段)

Android简易音乐重构MVVMJava版-使用Navigation导航组件重构主界面及其他页面跳转(二十)关于效果图实现修改Activity_main.xml页面修改MainActivity.java新建一个libCommon的library(一些kotlin写的工具放在这里)修改nav_graph.xml... 查看详情

BerkeleyDB-Core-JAVA 中的内存日志缓冲区大小

】BerkeleyDB-Core-JAVA中的内存日志缓冲区大小【英文标题】:In-memorylogbuffersizeinBerkeleyDB-Core-JAVA【发布时间】:2011-07-1208:26:50【问题描述】:我在BerkeleyBerkeleyDB-Core-JAVA版本中使用内存日志缓冲区。我有9个缺少记录的CDRFile。当我在... 查看详情

c语言实现windows,linux双版本下的进度条小程序,快来试一试吧(代码片段)

文章目录C语言缓冲区🚀1.输入缓冲区🍇模拟登录密码场景🍇从键盘将内容输入到内存的真正过程🍇解决方法:清空输入缓冲区🍉清掉一个字符🍉清空输入缓冲区所有字符🚀2.用户C语言级别的缓... 查看详情

基于c++实现的文件系统(简易版——内存空间操作)(代码片段)

文章目录基于C++实现的文件系统(简易版——内存空间操作)一、实现的相关操作:1.1目录相关操作1.2文件相关操作1.3系统操作二、系统层次结构:三、磁盘管理3.1磁盘向文件管理提供的接口说明:3.2文件层次管... 查看详情

双缓存解决闪烁问题(代码片段)

双缓存解决闪烁问题原文链接:https://www.cnblogs.com/owenlang/p/3916989.html   staticHDChdcBackBuffer;staticHBITMAPhBitmap;staticHBITMAPhOldBitmap;//创建后备缓冲器//1.用CreateCompatibleDC创建一个内存设备,得到后备缓冲区的hdc;hdcBackBuf 查看详情

springbootlogback日志组件使用(代码片段)

...   Logback是一个开源日志组件。Logback一般和SLF4结合起来使用。外层使用SLF4J,里面的实现是logback。什么意思,简单来说我们使用层看到的是SLF4J。我们使用的时候就是和SLF4J提供的一些api打交道。    我们可能经常听到SLF4J,... 查看详情

简易内存分配器的实现(代码片段)

...存管理器实现总体结构如下所示:该内存分配器的刚开始使用是通过sc_pool_s*sc_create_pool(size_tsize)函数创建一个字节大小为size的sc_pool_s对象,该对象由一个链表结构的sc_pool_data_t和一个指向sc_pool_large_s的结构体指针组成,其中sc_poo... 查看详情

13.4-全栈java笔记:打飞机游戏实战项目|offscreenimage|gameobject|plane

...冲技术”的绘图过程如下:a.在内存中创建与画布一致的缓冲区b.在缓冲区画图c.将缓冲区位图拷贝到当前画布上e.释放内存缓冲区双缓冲即在内存中创建一个与屏幕绘图区域一致的对 查看详情

javaawt图形界面编程canvas组件中使用graphics绘图④(awt绘图窗口闪烁问题)(代码片段)

...毕之前界面是空白的,这是闪烁产生的原因;引入一个图片缓冲区,绘制的时候向缓冲区绘制,然后直接将缓冲区同步到画布上,这样就避免了界面空白情况,保证始终界面上有内容;这就是双缓冲机制的原理;一、AWT绘图窗口闪烁问题使... 查看详情

java示例代码_查找Java可以使用多少直接缓冲区内存

java示例代码_查找Java可以使用多少直接缓冲区内存 查看详情

[linux]缓冲区的理解以及简易模拟实现封装c标准库

...才能将内容刷新到指定文件呢?我们当时回答是因为存在缓冲区。那么本篇文章我们将重点了解认识一下缓冲区。0.什么是缓冲区?缓冲区的本质就是一段内存。那么这段内存在哪里呢?我们接下来将会说明这个问题。1.为什么... 查看详情