Javaベースの簡単なテキストログレコーダを共有し、毎秒10万件の書き込み速度を達成


これは私がCSDNの上の第1篇のブログで、后で私はここでいくつか私の个人が役に立つと思う小さいコンポーネント、フレームワーク、オリジナルのプロジェクトのソースコードなどを分かち合います.简単に自分を绍介して、私は10年働いて、早い数年従事します.Net関連の開発作業は、近年を除いて.Netは長い間java関連プラットフォームの開発を学び始めた.(会社のプロジェクトに必要な).本人の学歴、技術レベルは普通で、もちろんインターネットの大工場には行けませんが、私はやはり新しいことを勉強するのが好きで、できるだけ多く研究して自分の全体の実力を高めるのが好きです.私にとって技術の大工場に行くのはとっくに私の目標ではありません.私の最大の夢は生きている間に同じ志を持つ人と一緒に仕事をすることです.業は、大小にかかわらず社会的価値があればよい.では、本題に戻ります.次に、私が分かち合うものについて直接話します.
1.コンポーネント構造
コンポーネントは簡単です.javaクラスの名前はTxtLogger 2で、windowsとlinuxの下で使用でき、3つの静的インタフェースを提供します.
//       ,          
public static void SetRootDir(String rootString)

public static void log(Throwable ex, LogFileCreateType logFileCreateType, String customDir)

public static void log(String log, LogTye logTye, LogFileCreateType logFileCreateType, String customDir)

2.コンポーネント処理ロジック
簡単に言えば、内部にスレッドの安全なキューを提供し、基本的な生産、消費者モデルの方式で動作する.内部には別々のスレッドが消費され、ファイルバッファフローによってバッチで書き込まれます.
3.呼び出し方式
 for (int i = 0; i < 100000; i++) {
            String log = "                  ,             !    :" + i;
            //  
            TxtLogger2.log("info" + log, TxtLogger2.LogTye.INFO, TxtLogger2.LogFileCreateType.OneFileEveryDay, "");
            TxtLogger2.log("debug" + log, TxtLogger2.LogTye.Debug, TxtLogger2.LogFileCreateType.OneFileEveryDay, "");
            TxtLogger2.log("error" + log, TxtLogger2.LogTye.ERROR, TxtLogger2.LogFileCreateType.OneFileEveryDay, "");
            //   
            TxtLogger2.log(log, TxtLogger2.LogTye.INFO, TxtLogger2.LogFileCreateType.OneFileAnHour, "");
            TxtLogger2.log(log, TxtLogger2.LogTye.Debug, TxtLogger2.LogFileCreateType.OneFileAnHour, "");
            TxtLogger2.log(log, TxtLogger2.LogTye.ERROR, TxtLogger2.LogFileCreateType.OneFileAnHour, "");
            //  10  
            TxtLogger2.log(log, TxtLogger2.LogTye.INFO, TxtLogger2.LogFileCreateType.OneFilePerTenMinutes, "");
            TxtLogger2.log(log, TxtLogger2.LogTye.Debug, TxtLogger2.LogFileCreateType.OneFilePerTenMinutes, "");
            TxtLogger2.log(log, TxtLogger2.LogTye.ERROR, TxtLogger2.LogFileCreateType.OneFilePerTenMinutes, "");

            //    
            TxtLogger2.log(log, TxtLogger2.LogTye.INFO, TxtLogger2.LogFileCreateType.OneFilePerMinute, "");
            TxtLogger2.log(log, TxtLogger2.LogTye.Debug, TxtLogger2.LogFileCreateType.OneFilePerMinute, "");
            TxtLogger2.log(log, TxtLogger2.LogTye.ERROR, TxtLogger2.LogFileCreateType.OneFilePerMinute, ""); 
        }

4.テスト結果
ログ・コンポーネントは、ユーザー・コール・パラメータに基づいて設定されたログ・タイプと、カスタム・ディレクトリに基づいて、対応するディレクトリとファイル(年月日/10分/分ごとのディレクトリ構造など)を動的に作成することができるため、実際のプロジェクト・マルチスレッド環境では、不確定な数の異なるパスのファイルが同時に作成される場合があります.私は1つの単一スレッドで10万回連続して送信し、毎回10個の異なるファイルのログ記録をテストし、合計100万個のデータを記録したことに相当します.ideaでテストしたところ、メインスレッド呼び出しログインタフェースは約5秒程度で、実際のログ内部にディスクがすべて書き込まれるのは10秒程度でした.興味があれば自分でテストして改善し続けることができます!
以上私はすべてのソースコードを貼り出して、興味のある友达は自分でダウンロードします
package logger2;

import java.io.*;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ConcurrentLinkedQueue;

/***
 * this java class is created by huchengdong 2018/8/22
 * this is a simple txt log writer
 */
public class TxtLogger2 {
    private  static  String dirName="AppLog1";
    private static String rootDirString = "C:/"+dirName;
    private static String enterString = "\r
"; private static int saveCountPer = 4000; // static ConcurrentLinkedQueue concurrentLinkedQueue = new ConcurrentLinkedQueue<>(); static { try { if (new File("D:/").exists()) { rootDirString = "D:/"+dirName; } else if (new File("E:/").exists()) { rootDirString = "E:/"+dirName; } Properties props = System.getProperties(); String os_name = props.getProperty("os.name").toLowerCase(); if (os_name != null && !os_name.contains("windows")) { rootDirString = "/usr/"+dirName; enterString = "
"; } // Thread thread = new Thread() { public void run() { handQueue(); } }; thread.setDaemon(true); thread.start(); } catch (Exception ex) { ex.printStackTrace(); } } public static void SetRootDir(String rootString) { rootDirString = rootString; } private static void handQueue() { List list = new ArrayList<>(); FileItem fileItem = null; while (true) { try { fileItem = concurrentLinkedQueue.poll(); if (fileItem != null) { list.add(fileItem); // , if (list.size() >= saveCountPer) { writeToDisk2(list); list.clear(); } } else { // , writeToDisk2(list); list.clear(); } // CPU if (concurrentLinkedQueue.isEmpty()) { Thread.sleep(1); } } catch (Exception ex) { ex.printStackTrace(); } } } /** * * @param list * @throws IOException */ private static void writeToDisk2(List list) throws IOException { if (list == null || list.size() == 0) return; BufferedWriter out = null; Map map = new HashMap<>(100); for (FileItem item : list) { if (map.containsKey(item.getFilePath())) { map.get(item.getFilePath()).write(item.getLog() + enterString); } else { String dirPath = item.getFilePath().substring(0, item.getFilePath().lastIndexOf("/")); File file = new File(dirPath); if (!file.exists()) { file.mkdirs(); } file = new File(item.getFilePath()); if (!file.exists()) { file.createNewFile(); } out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file, true), "utf-8")); out.write(item.getLog() + enterString); map.put(item.getFilePath(), out); } } for (BufferedWriter bufferedWriter : map.values()) { try { bufferedWriter.flush(); bufferedWriter.close(); } catch (Exception ex) { } } } /** * * * @param ex * @param logFileCreateType * @param customDir */ public static void log(Throwable ex, LogFileCreateType logFileCreateType, String customDir) { StringBuffer sb = new StringBuffer(); for (StackTraceElement element : ex.getStackTrace()) { sb.append(element.toString() + enterString); } log(ex.getMessage() + " " + sb.toString(), LogTye.ERROR, logFileCreateType, customDir); } /** * * * @param log * @param logTye * @param logFileCreateType * @param customDir */ public static void log(String log, LogTye logTye, LogFileCreateType logFileCreateType, String customDir) { try { String path = rootDirString; String filePath = ""; if (customDir == null || customDir.length() <= 0) { } else { path += "/" + customDir; } path += "/" + logTye.name(); Calendar c = Calendar.getInstance();// int year = c.get(Calendar.YEAR); int month = c.get(Calendar.MONTH) + 1; int date = c.get(Calendar.DATE); int hour = c.get(Calendar.HOUR_OF_DAY); int minute = c.get(Calendar.MINUTE); int second = c.get(Calendar.SECOND); if (logFileCreateType == LogFileCreateType.OneFileEveryDay) { path += "/" + year + "/" + month; filePath = path + "/" + date + ".log"; } else if (logFileCreateType == LogFileCreateType.OneFileAnHour) { path += "/" + year + "/" + month + "/" + date; filePath = path + "/" + hour + ".log"; } else if (logFileCreateType == LogFileCreateType.OneFilePerTenMinutes) { path += "/" + year + "/" + month + "/" + date + "/" + hour; filePath = path + "/" + WhichTenMinutes(minute) + ".log"; } else if (logFileCreateType == LogFileCreateType.OneFilePerMinute) { path += "/" + year + "/" + month + "/" + date + "/" + hour; filePath = path + "/" + minute + ".log"; } Date now = new Date(); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss.SSS"); // concurrentLinkedQueue.add(new FileItem(filePath, dateFormat.format(now) + ":" + log)); } catch (Exception e) { e.printStackTrace(); } } private static String WhichTenMinutes(int minute) { return String.valueOf(minute / 10 + 1)+"_10"; } public enum LogTye { Debug, INFO, ERROR; } public enum LogFileCreateType { OneFileEveryDay, OneFileAnHour, OneFilePerTenMinutes, OneFilePerMinute } static class FileItem { public String getFilePath() { return filePath; } public String getLog() { return log; } private String filePath; private String log; public FileItem(String filePath, String log) { this.filePath = filePath; this.log = log; } } }