最近在对一个系统做性能优化!
现状分析:
该系统有三类线程:
A类-接收线程: 从mq中获取消息(消息字符数大约1千至3千个字符);该类线程可以启动多个,因为可以从多个mq队列获取消息;
B类-处理线程: 获取A类线程接收的消息并进行解析和逻辑处理,最后生成新的消息传递给C类线程,B类线程是单线程;
C类-发送线程: 将B类线程生成的新消息(新消息字符数大约2千至9千个字符),发送给多个mq队列,C类线程为多个线程;
A类线程调用A_Logger日志对象打印接收到的消息(有1+个A类线程共享A_Logger日志对象);
B类线程调用B_Logger日志对象打印处理过程中的日志以便跟踪处理流程(单个B线程会在处理过程中多次打印处理日志);
C类线程调用C_Logger日志对象打印B类线程处理后生成的消息(有1+个C类线程共享C_Logger对象);
//注释:这里的logger日志对象用的是log4j
分析:
- 因为对一个logger对象进行调用的时候,logger是会被加锁的,所以多线程同时调用一个logger的时候,其实它们是串行执行的;
- 打印日志这种事,完全跟当前的业务处理逻辑没有任何关系,所以可以考虑使用单独的线程去做这种事;
改造方案:
- 为每一类Logger日志对象创建单独的线程,在线程里面负责真正的日志打印(因为日志对象不是很多,所以这样创建的线程也不会很多);
- 将在程序中调用Logger对象打印日志的操作修改为把需要打印的日志内容传递给相应的日志打印线程来处理;
- 尽量避免对程序中打印日志部分代码的修改;这个时候就能使用装饰者模式(Decorator)了;
Decorator定义:
动态给一个对象添加一些额外的职责,就象在墙上刷油漆.使用Decorator模式相比用生成子类方式达到功能的扩充显得更为灵活.
package kpicomm;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.LinkedBlockingQueue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import DBUtil.MethodTime;
/**
* 异步日志打印组件!
*
* 该类用作将日志操作从当前的业务线程中分离出来,交给单独的日志打印线程来操作;
* 该类的实现依赖于slf4j;
*
* 使用方法:
* 1.调用静态的LoggerAsyn.getLogger获取日志组件;(初始调用会创建一个异步日志组件,并作为线程运行);
* 2.像log4j,slf4j一样调用isDebugEnabled,debug等方法;
* 3.LoggerAsyn.removeLogger删除对应日志组件,并且停止线程;
*
* @author LostHu
*
*/
public class LoggerAsyn extends LoggerAsynAdapter implements Runnable{
static private Map<Logger ,Logger > loggerMap = new HashMap<Logger, Logger>();
private MethodTime methodTime = new MethodTime();
/**
* 根据日志组件名称获取异步日志打印组件
* @param loggerName 日志组件名称
* @return
*/
public static Logger getLogger(String loggerName){
Logger logger = LoggerFactory.getLogger(loggerName);
return getLogger(logger);
}
/**
* 根据slf4j日志组件对象获取异步日志打印组件
* @param logger slf4j日志组件对象
* @return
*/
public static Logger getLogger(Logger logger){
Logger loggerReturn = null;
synchronized (loggerMap) {
loggerReturn = loggerMap.get(logger);
if (loggerReturn == null){
loggerReturn = new LoggerAsyn(logger);
loggerMap.put(logger, loggerReturn);
new Thread((LoggerAsyn)loggerReturn).start();
}
}
return loggerReturn;
}
/**
* 删除日志组件名称对应的异步日志打印组件,并停止该日志打印线程
* @param loggerName 日志组件名称
* @return
*/
public static boolean removeLogger(String loggerName){
Logger logger = LoggerFactory.getLogger(loggerName);
return removeLogger(logger);
}
/**
* 删除slf4j日志组件对象对应的异步日志打印组件,并停止该日志打印线程
* @param loggerName slf4j日志组件对象
* @return
*/
public static boolean removeLogger(Logger logger){
if (logger == null) return true;
Logger loggerReturn = null;
synchronized (loggerMap) {
loggerReturn = loggerMap.get(logger);
if (loggerReturn != null){
((LoggerAsyn)loggerReturn).isRunning = false;
}
loggerMap.remove(logger);
}
return true;
}
/**
* 真实被委托打印的日志对象
*/
private Logger realLogger ;
/**
* 日志组件线程是否运行
*/
private volatile boolean isRunning = true;
public Logger getRealLogger() {
return realLogger;
}
/**
* 私有的构造方法,只有在静态的getLogger才被调用;
* 传入的日志打印组件为null的时候,会默认一个名字为LoggerAsyn的日志对象(避免这种情况)
* @param logger 真实的日志打印组件;
*/
private LoggerAsyn(Logger logger) {
super();
this.realLogger = logger;
if (this.realLogger==null){
this.realLogger = LoggerFactory.getLogger("LoggerAsyn");
}
}
LinkedBlockingQueue<LogEvent> clq = new LinkedBlockingQueue<LogEvent>();
LinkedBlockingQueue<LogEvent> getClq() {
return clq;
}
public void run(){
Thread.currentThread().setName(getRealLogger().getName());
LogEvent logEvent = null;
while(isRunning){
try {
logEvent = getClq().take();
if (isRunning){
if (logEvent!=null){
methodTime.start(getRealLogger().getName());
switch (logEvent.getLog_level()) {
case LoggerAsyn.DEBUG_LEVEL:
getRealLogger().debug(logEvent.getLogString());
break;
case LoggerAsyn.INFO_LEVEL:
getRealLogger().info(logEvent.getLogString());
break;
case LoggerAsyn.WARN_LEVEL:
getRealLogger().warn(logEvent.getLogString());
break;
case LoggerAsyn.ERROR_LEVEL:
getRealLogger().error(logEvent.getLogString());
break;
default:
getRealLogger().info(logEvent.getLogString());
break;
}
methodTime.end(getRealLogger().getName());
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
* 日志打印事件对象
* @author LostHu
*
*/
class LogEvent{
/**
* 日志打印的级别
*/
int log_level;
/**
* 日志打印的内容
*/
String logString;
public LogEvent(int log_level, String logString) {
super();
this.log_level = log_level;
this.logString = logString;
}
public int getLog_level() {
return log_level;
}
public void setLog_level(int log_level) {
this.log_level = log_level;
}
public String getLogString() {
return logString;
}
public void setLogString(String logString) {
this.logString = logString;
}
}
@Override
public void debug(String arg0) {
LogEvent le = new LogEvent(LoggerAsyn.DEBUG_LEVEL,arg0);
clq.add(le);
}
@Override
public void info(String arg0) {
LogEvent le = new LogEvent(LoggerAsyn.INFO_LEVEL,arg0);
clq.add(le);
}
@Override
public void warn(String arg0) {
LogEvent le = new LogEvent(LoggerAsyn.WARN_LEVEL,arg0);
clq.add(le);
}
@Override
public void error(String arg0) {
LogEvent le = new LogEvent(LoggerAsyn.ERROR_LEVEL,arg0);
clq.add(le);
}
@Override
public boolean isDebugEnabled() {
return getRealLogger().isDebugEnabled();
}
@Override
public boolean isInfoEnabled() {
return getRealLogger().isInfoEnabled();
}
@Override
public boolean isWarnEnabled() {
return getRealLogger().isWarnEnabled();
}
@Override
public boolean isErrorEnabled() {
return getRealLogger().isErrorEnabled();
}
}
代码解释:
LoggerAsyn是实现org.slf4j.Logger接口,是对真实Logger对象的装饰者(因为真正的日志打印还是委托给真实的Logger对象)
使用LoggerAsyn对象去改造程序:
改造前代码:
private static Logger log = LoggerFactory.getLogger("xxxx");
改造后代码
private static Logger log_proc = LoggerAsyn.getLogger("xxxx");
非常简单,改动量非常非常小!
源代码请见附件!
分享到:
相关推荐
Java类库中Decorator模式的应用研究
java Decorator设计模式应用,可以简单了解它,初学者入。
C#设计模式之Decorator 装饰模式,pdf+视频教学,实例演示,易学易用~~
DateFormat,Calendar、文件与流、Java变量类型间的相互转换、Java与Web、用连接池提高Servlet访问数据库的效率、Java扩展、应用服务器的集群策略及Java EE 5.0、Java IO 包中的Decorator模式等。
装饰模式(Decorator),动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活。
结构模式:设计模式之Facade(外观),设计模式之Proxy(代理),设计模式之Adapter(适配器),设计模式之Composite(组合),设计模式之Decorator(油漆工),设计模式之Bridge,设计模式之Flyweight(享元). 行为模式:设计模式之...
如果你想要深入透彻地理解和掌握设计模式,并期望能真正把设计模式应用到项目中去,那么这是你不可错过的一本好书。 《研磨设计模式》难度为初级到中级,适合与所有开发人员、设计人员或者即将成为开发人员的朋友。...
九、 一个实际应用Composite模式的例子 98 C#设计模式(12)-Decorator Pattern 101 一、 装饰(Decorator)模式 101 二、 装饰模式的结构 102 三、 装饰模式示例性代码 103 四、 装饰模式应当在什么情况下使用 106...
第12章 装饰者模式(Decorator) 12.1 模式解说 12.2 结构和用法 12.2.1 模式结构 12.2.2 代码模板 12.2.3 问题讨论 12.3 范例与实践 12.3.1 装饰者模式在图片观赏器中的应用 12.3.2 范例小结 第13章 门面...
5.1.2 Decorator模式 5.1.3 Template Method模式 5.1.4 State模式 5.1.5 Strategy模式 5.2 应用企业模式 5.2.1 Specification模式 5.2.2 Composite模式 5.2.3 Layer Supertype模式 5.3 应用设计原则 5.3.1...
第12章 装饰者模式(Decorator) 12.1 模式解说 12.2 结构和用法 12.2.1 模式结构 12.2.2 代码模板 12.2.3 问题讨论 12.3 范例与实践 12.3.1 装饰者模式在图片观赏器中的应用 12.3.2 范例小结 第...
2.4.3 Decorator 模式 32 2.5 支持多种视感标准 32 2.5.1 对象创建的抽象 32 2.5.2 工厂类和产品类 33 2.5.3 Abstract Factory模式 35 2.6 支持多种窗口系统 35 2.6.1 我们是否可以使用Abstract Factory 模式 35 ...
七、 一个实际应用Adapter模式的例子 八、 关于Adapter模式的讨论 C#设计模式(11)-Composite Pattern 一、 合成(Composite)模式 二、 合成模式概述 三、 安全式的合成模式的结构 四、 安全式的合成模式...
4. **装饰者模式(Decorator Pattern)**:装饰者模式是一种结构设计模式,允许向一个对象动态添加新功能,而无需修改其源代码。 5. **策略模式(Strategy Pattern)**:策略模式是一种行为设计模式,定义了一系列...
如果你想要深入透彻地理解和掌握设计模式,并期望能真正把设计模式应用到项目中去,那么这是你不可错过的一本好书。 《研磨设计模式》难度为初级到中级,适合与所有开发人员、设计人员或者即将成为开发人员的朋友。...
本文实例讲述了PHP设计模式之装饰器(装饰者)模式(Decorator)入门与应用。分享给大家供大家参考,具体如下: 通常情况下,我们如果要给对象添加功能,要么直接修改对象添加相应的功能,要么派生对应的子类来扩展...
Laravel应用中的装饰器模式 用 :red_heart: 用于智能清洁编码器 尝试将“装饰器”功能从python语言移植到laravel框架。 :delivery_truck: 安装 : composer require imanghafoori/laravel-decorator 什么是...
一、装饰者模式(Decorator Pattern) 20 二、装饰者模式的特性 21 【三】、简单工厂模式 22 简单工厂模式(Simply Factory Pattern) 22 【四】、门面模式 23 一、门面模式(Facade Pattern) 23 二、门面模式的结构 24 ...