1、效率
log4j关闭debug级别输出,但是在代码中log.debug(Object msg)的写法不同,将会多耗费3-5倍的时间。因此,要优化log.debug()这个方法的调用的,log.info()也是同理。
2、log4j的优化简介
log4j做了大量的优化,比如:Log4j初始化时打开文件并保持对文件的写控制,直到进程结束时才关闭流。这样控制打开I/O次数。
还有其他方面的优化,使用了大量缓存,参看debug方法源码
public void debug(Object message) {
if(repository.isDisabled(Level.DEBUG_INT))
return;
if(Level.DEBUG.isGreaterOrEqual(this.getEffectiveLevel())) {
forcedLog(FQCN, Level.DEBUG, message, null);
}
}
设置输出级别为INFO时,调用debug()会直接返回。但在使用LOG.debug("business is" + xxxObj)时,虚拟机在debug方法执行前需要先将字符串进行连接,这就是俺们需要优化的地方。
3、效率编码及测试
下面上干货,fuck goods
测试工具类TestUtil
package util;
public class TestUtil {
/**
*
* 测试函数使用时间,通过定义TestCallBack接口的execute方法
*
* @param testCallBack
*/
public static long testTime(TestCallBack testCallBack) {
long begin = System.currentTimeMillis(); // 测试起始时间
testCallBack.execute(); // /进行回调操作
long end = System.currentTimeMillis(); // 测试结束时间
long cost = (end - begin);
return cost;
}
}
回调函数
package util;
public interface TestCallBack {
public void execute();
}
测试主类
package util;
import org.apache.log4j.Logger;
import util.TestCallBack;
import util.TestUtil;
public class EfficientTest {
private final static Logger LOG = Logger.getLogger(EfficientTest.class);
private final static int MAX_LOOP = 100 * 1000 * 1000;
/**
* 正常写法
*/
public long log() {
long cost = TestUtil.testTime(new TestCallBack() {
@Override
public void execute() {
for (int i = 0; i < MAX_LOOP; i++) {
/**
* "test" + "abc" + str的写法,会在运行时产生运算
*/
String str = "tt";
LOG.debug("test" + "abc" + str);
/**
* "test" + "abc"的写法,虚拟机在编译器会合并直接量,运行时并不会运算
*/
// LOG.debug("test" + "abc");
}
}
});
System.out.println(" cost:" + cost);
return cost;
}
/**
* 效率写法
*/
public long logEfficient() {
long cost = TestUtil.testTime(new TestCallBack() {
@Override
public void execute() {
for (int i = 0; i < MAX_LOOP; i++) {
if (LOG.isDebugEnabled()) {
String str = "tt";
LOG.debug("test" + "abc" + str);
// LOG.debug("test" + "abc");
}
}
}
});
System.out.println("efficient cost:" + cost);
return cost;
}
public static void main(String[] args) {
EfficientTest test = new EfficientTest();
for (int i = 0; i <= 9; i++) {
System.out.println("====我是华丽的分割线====" + i);
if (i % 2 > 0) {
long log = test.log();
long logEfficient = test.logEfficient();
System.out.println("log/logEfficient,"
+ (((double) log / logEfficient) * 100.0)
+ "% increase");
} else {
long logEfficient = test.logEfficient();
long log = test.log();
System.out.println("log/logEfficient,"
+ (((double) log / logEfficient) * 100.0)
+ "% increase");
}
// System.out.println();
}
}
}
log4j配置类,把输出级别调整成INFO级别
log4j.rootCategory=INFO, stdout log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.Target=System.out log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%p [%t] %C.%M(%L) | %m%n
运行后的结果
====我是华丽的分割线====0
efficient cost:434
cost:2054
log/logEfficient,473.2718894009216% increase
====我是华丽的分割线====1
cost:1822
efficient cost:434
log/logEfficient,419.8156682027649% increase
====我是华丽的分割线====2
efficient cost:394
cost:1823
log/logEfficient,462.69035532994917% increase
====我是华丽的分割线====3
cost:1805
efficient cost:400
log/logEfficient,451.25% increase
====我是华丽的分割线====4
efficient cost:400
cost:1805
log/logEfficient,451.25% increase
====我是华丽的分割线====5
cost:1790
efficient cost:396
log/logEfficient,452.02020202020196% increase
====我是华丽的分割线====6
efficient cost:397
cost:1798
log/logEfficient,452.89672544080605% increase
====我是华丽的分割线====7
cost:1786
efficient cost:393
log/logEfficient,454.45292620865143% increase
====我是华丽的分割线====8
efficient cost:401
cost:1969
log/logEfficient,491.0224438902743% increase
====我是华丽的分割线====9
cost:1801
efficient cost:392
log/logEfficient,459.4387755102041% increase
优化效果显而易见,关闭DEBUG级别的日志后,log.debug方法的写法不同,造成运行时间也不同
4、类似的方法
除了
LOG.isDebugEnabled()
还有
LOG.isInfoEnabled()
还有
LOG.isEnabledFor(Priority.DEBUG);
Log4j的HelloWorld 在javaSE中入门使用一
Log4j使用的效率二
Log4j的输出格式三
Log4j将System.out搞到log4j中输出四