Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
是否有一种使用默认Java库为控制台输出添加时间戳的正确方法?_Java_Performance_Logging - Fatal编程技术网

是否有一种使用默认Java库为控制台输出添加时间戳的正确方法?

是否有一种使用默认Java库为控制台输出添加时间戳的正确方法?,java,performance,logging,Java,Performance,Logging,当我处理个人Java项目时,我喜欢有一种将文本很好地记录到控制台的方法。我通常为此创建一些公共静态类来处理消息的前缀和时间戳,这样我就可以省略System.out.println(“Text”);的用法 这是我不久前编写的一个类,我倾向于在不同的项目上重用它,因为我非常喜欢它格式化文本的方式: import java.text.SimpleDateFormat; import java.util.Date; public class Log { public static final

当我处理个人Java项目时,我喜欢有一种将文本很好地记录到控制台的方法。我通常为此创建一些公共静态类来处理消息的前缀和时间戳,这样我就可以省略System.out.println(“Text”);的用法

这是我不久前编写的一个类,我倾向于在不同的项目上重用它,因为我非常喜欢它格式化文本的方式:

import java.text.SimpleDateFormat;
import java.util.Date;

public class Log {

    public static final int LEVEL_INFO = 0;
    public static final int LEVEL_WARNING = 1;
    public static final int LEVEL_ERROR = 2;

    private static SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss");
    /**
     * Used instead of System.out.println for consistent formatting.
     *
     * @param messageToPrefix Message that you want to send to print.
     * @param errorLevel Type of message you want to send.
     */
    public static void print(String messageToPrefix, int errorLevel) {
        StringBuilder message = new StringBuilder();
        message.append("[").append(df.format(new Date())).append("] ");
        switch(errorLevel) {
            case LEVEL_INFO:
                 message.append("[Info] ");
                break;
            case LEVEL_WARNING:
                message.append("[Warning] ");
                break;
            case LEVEL_ERROR:
                message.append("[Error] ");
                break;
        }
        message.append(messageToPrefix);
        System.out.println(message.toString());
    }
}
这一切都如预期的那样有效,但我刚才注意到了一个小问题:这种创建时间戳的方法非常耗费资源!调用它需要我想要记录的代码停止,直到时间戳被创建并写入控制台。这对我来说似乎效率低下(即使我们在这里讨论的是几毫秒)。当我将此日志记录方法的运行时与使用System.currentTimeMillis()的运行时进行比较时,我得出了这个结论。System.currentTimeMillis()并没有将其格式化为一个好的时间戳,但如果这样使用,则以毫秒为单位显示运行时:

public class Log {

    private static final long startTime = System.currentTimeMillis();

    public static final int LOG_LEVEL_INFO = 0;
    public static final int LOG_LEVEL_WARNING = 1;
    public static final int LOG_LEVEL_ERROR = 2;
    public static final int LOG_LEVEL_UNKNOWN = 3;

    /**
     * Used instead of System.out.println for consistent formatting.
     *
     * @param msg Message that you want to send to log.
     * @param importance How important is the message?
     */
    public static void print(String msg, int importance) {
        StringBuilder finalMsg = new StringBuilder();
        finalMsg.append("[").append(System.currentTimeMillis() - startTime).append(" ms] ");
        switch (importance) {
            case 0:
                finalMsg.append("[INFO] ");
                break;
            case 1:
                finalMsg.append("[WARNING] ");
                break;
            case 2:
                finalMsg.append("[ERROR] ");
                break;
            default:
                finalMsg.append("[UNKNOWN] ");
                break;
        }
        finalMsg.append(msg);
        System.out.println(finalMsg);
    }
}
事实证明,这种方式即使是在小规模上也要快得多,比如在大约50秒的运行时间内发送50条消息

这让我思考了几个问题: 有没有更好的方法来创建这样的时间戳? 有没有办法不等待日志代码完成? 为此开始一个线程是个好主意吗? 还是我完全走错了路

我不想使用任何额外的库来保持它的小而简单


任何建议都将不胜感激

编辑:好的,我认为(在遵循一些建议之后)这是一种安全的方式来记录和标记消息。这可能不是最快的方法,但它是安全的使用,并给了我想要的结果

import java.text.SimpleDateFormat;
import java.util.Date;

    public class Log {

        public static final int LEVEL_INFO = 0;
        public static final int LEVEL_WARNING = 1;
        public static final int LEVEL_ERROR = 2;

        private static final ThreadLocal<SimpleDateFormat> formatter = ThreadLocal.withInitial(() -> new SimpleDateFormat("HH:mm:ss"));

        /**
         * Used instead of System.out.println for consistent formatting.
         *
         * @param messageToPrefix Message that you want to send to print.
         * @param errorLevel Type of message you want to send.
         */
        public static void print(String messageToPrefix, int errorLevel) {
            StringBuilder message = new StringBuilder();
            message.append("[").append(formatter.get().format(new Date())).append("] ");
            switch(errorLevel) {
                case LEVEL_INFO:
                    message.append("[Info] ");
                    break;
                case LEVEL_WARNING:
                    message.append("[Warning] ");
                    break;
                case LEVEL_ERROR:
                    message.append("[Error] ");
                    break;
            }
            message.append(messageToPrefix);
            System.out.println(message.toString());
        }
    }
import java.text.simpleDataFormat;
导入java.util.Date;
公共类日志{
公共静态最终整数级别_INFO=0;
公共静态最终整数级警告=1;
公共静态最终整数级_错误=2;
私有静态最终ThreadLocal格式化程序=ThreadLocal.withInitial(()->新SimpleDataFormat(“HH:mm:ss”);
/**
*用于替代System.out.println以获得一致的格式。
*
*@param messageToPrefix您要发送打印的消息。
*@param errorLevel您要发送的消息类型。
*/
公共静态无效打印(字符串messageToPrefix,int errorLevel){
StringBuilder消息=新建StringBuilder();
message.append(“[”).append(formatter.get().format(new Date())).append(“]);
开关(错误级别){
案例级别信息:
message.append(“[Info]”);
打破
案例级别警告:
message.append(“[警告]”);
打破
案例级错误:
message.append(“[Error]”);
打破
}
message.append(messageToPrefix);
System.out.println(message.toString());
}
}

我要感谢评论中的人提供的所有建议。

使用日志库,例如内置的,也被称为JUL。另一个注释:。虽然修复这个问题可能会进一步增加处理时间。@Andreas我明白了。老实说,我不知道它的存在。我会试试的,谢谢。@Marvin Yikes!感谢您的警告。只有在多线程访问应用程序状态的并发环境中运行应用程序时,线程安全才重要。如果这不是真的,锁定会减慢程序的速度。由于这个原因,一些线程安全类(如StringBuffer)被重新实现(作为StringBuilder)。一些线程安全类,例如BigInteger,附带了可变伴生类(位集),用于特定的性能场景。您编写的类似乎是线程安全的,但可变SimpleDataFormat除外。使用Java日期时间库中的相应类,其对象是不可变的(因此始终是线程安全的),将允许您的程序保持线程安全,而无需锁定。同意scottb。如果可以的话,选择Java日期时间库,放弃那些过时的废话。即使没有Java 8,您也可以,因为有一个后端口使用线程不安全的部分时,请考虑使用<代码>线程本地< /COD> ++。考虑将最后一毫秒与格式化字符串一起存储为单个元素缓存。尽管我相信
java.time
优化程度很高,但即使是在现代图书馆中,这也可能很有用。@maaartinus我明白了。这似乎是一个更好的解决方案。我想我会使用我的原始类,然后使用initialValue方法将SimpleDataFormat放在ThreadLocal对象中。请注意,
ThreadLocal.initialValue
在(web服务器)容器中重新部署应用程序时会造成内存泄漏。但你可能没有,所以没关系