客户端使用,代码清洁,装饰器模式
public class JobHandlerAsyncDemo {
public static class JobHandlerDirect implements IJobHandler<String> {
@Override
public void doJob(String job) {
System.out.println("do job ..."+job);
}
}
public static void main(String[] args) {
IJobHandler<String> jobHandlerDirect = new JobHandlerDirect();//同步的
IJobHandler<String> jobHanderAsync = new JobHandlerAsync<String>(3,500,"JobHand",jobHandlerDirect);//同步转换成异步
jobHanderAsync.doJob("1");
jobHanderAsync.doJob("2");
jobHanderAsync.doJob("3");
}
}
先告诉我,如果不异步的时候,需要如何处理?实现IJobHandler接口
public interface IJobHandler<T> {
public void doJob(T job);
}
装饰器JobHandlerAsync是如何把一个同步处理转换成异步处理的
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class JobHandlerAsync<T> implements JobHandlerAsyncMBean,IJobHandler<T> {
private static final Logger log = LoggerFactory.getLogger(JobHandlerAsync.class);
private int queueCapacity;
private BlockingQueue<Runnable> queue;
private ThreadPoolExecutor executor;
private IJobHandler<T> delegate;
private static final AtomicInteger instanceCount = new AtomicInteger(1);
private int instanceNum;
public JobHandlerAsync(int fixedThreadSize, int queueCapacity, String threadTag,IJobHandler<T> hbb) {
this(hbb, fixedThreadSize, fixedThreadSize, 1000*60*2, threadTag, fixedThreadSize, new LinkedBlockingQueue<Runnable>(queueCapacity));
}
public JobHandlerAsync(IJobHandler<T> hbb) {
/*
* 队列大小不宜太大,积压超过50个,立马要增加线程来处理;如果线程增加了,还是处理不过了,基本表示系统后方出问题了。
* 后方出问题了,应该尽管启动拒绝策略,决绝策略可以报警。
* 如果队列设置太大,导致即使处理不过来,也不会增加线程,更不会启动拒绝策略,意思就是:我现在处理不过来了,积压着吧,等我慢慢处理。
* 最终要么是队列增大,设置超过JVM内存,最终因为内存溢出而挂了;要么是客户端长时间等待,客户端认为超时,响应已经没有意义了。
* */
this(hbb, 5, 10, 1000*60*2, "JobHandler", 50);
}
public JobHandlerAsync(IJobHandler<T> hbb, int coreThreadSize, int maxThreadSize, int keepAliveSec,String threadTag, int queueCapacity) {
this(hbb, coreThreadSize, maxThreadSize, keepAliveSec, threadTag, queueCapacity, new LinkedBlockingQueue<Runnable>(queueCapacity));
}
protected JobHandlerAsync(IJobHandler<T> hbb, int coreThreadSize, int maxThreadSize, int keepAliveSec,String threadTag, int queueCapacity,BlockingQueue<Runnable> queue) {
this.threadTag = threadTag;
this.delegate = hbb;
this.queueCapacity = queueCapacity;
this.queue = queue;
RejectedExecutionHandler rejectedHandler = new AlertPolicy();
ThreadFactory threadFactory = new TagThreadFactory(threadTag);
this.executor = new ThreadPoolExecutor(coreThreadSize,maxThreadSize, keepAliveSec, TimeUnit.SECONDS, queue,threadFactory,rejectedHandler);
this.instanceNum = instanceCount.getAndIncrement();
/* 注册JMX */
String beanName = getMBeanName();
if (JmxMBeanManager.getInstance().isRegistered(beanName)) {
log.warn("MBean '{}' is already registered, removing...", beanName);
JmxMBeanManager.getInstance().unregisterMBean(beanName);
}
log.info("Registering MBean '{}'...", beanName);
JmxMBeanManager.getInstance().registerMBean(this, beanName);
}
private String threadTag;
private String getMBeanName() {
//return JMX_MBEAN_OBJ_NAME + "-" + instanceNum;
//"com.sohu.tv.live.counter:type=JobHandlerAsync"
//com.sohu.tv.utils.threads
return "com.sohu.tv.utils.threads:type="+threadTag + "-" + instanceNum;
}
/** 拒绝策略自己实现的意义:系统处理不过来的时候,可以短信告警,即使发现系统的问题。*/
public static class AlertPolicy implements RejectedExecutionHandler {
/* new ThreadPoolExecutor.AbortPolicy() Not Fit */
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
log.warn("reject alert Job: {}", r);//目前登记日志报警,可以发短信的
}
}
/** 线程工厂自己实现的意义:可以统计程序在什么时间段增加了线程;还能给线程起名称(这样jstack看起来方便)。*/
public static class TagThreadFactory implements ThreadFactory {
/* 代码取自: Executors.defaultThreadFactory(); */
static final AtomicInteger poolNumber = new AtomicInteger(1);
final ThreadGroup group;
final AtomicInteger threadNumber = new AtomicInteger(1);
final String namePrefix;
TagThreadFactory(String tagName) {
SecurityManager s = System.getSecurityManager();
group = (s != null)? s.getThreadGroup() :
Thread.currentThread().getThreadGroup();
namePrefix = tagName+"-P"+poolNumber.getAndIncrement() +"T";
}
/**线程名称:Tag-PnTm-timestamp*/
@Override
public Thread newThread(Runnable r) {
String namePostfix = "-"+System.currentTimeMillis();//系统调用,比较消耗性能,但是能标识线程是什么时候创建的
/*标识线程的创建时间,从某种意义上能看出这个线程被复用的程度*/
Thread t = new Thread(group, r,
namePrefix + threadNumber.getAndIncrement() + namePostfix,
0);
if (t.isDaemon())
t.setDaemon(false);
if (t.getPriority() != Thread.NORM_PRIORITY)
t.setPriority(Thread.NORM_PRIORITY);
return t;
}
}
@Override
public int getActiveThreadSize() {
return executor.getActiveCount();
}
@Override
public int getAliveThreadSize() {
return executor.getPoolSize();
}
@Override
public int getQueueSize() {
return queue.size();
}
@Override
public int getHistoricalPeekThreadSize() {
return executor.getLargestPoolSize();
}
@Override
public long getHistoricalTotalTaskCount() {
return executor.getTaskCount();
}
@Override
public long getHistoricalCompletedTaskCount() {
return executor.getCompletedTaskCount();
}
@Override
public int getCoreThreadSize() {
return executor.getCorePoolSize();
}
@Override
public int getMaxThreadSize() {
return executor.getMaximumPoolSize();
}
@Override
public int getQueueCapacity() {
return queueCapacity;
}
@Override
public void doJob(T job) {
executor.execute(new JobRunnable(job));
}
public class JobRunnable implements Runnable {
private final T job;
public JobRunnable(T attachment) {
this.job = attachment;
}
@Override
public void run() {
delegate.doJob(job);
}
@Override
public String toString() {
return job.toString();
}
}
@Override
public void shutdown() {
executor.shutdown();
}
@Override
public List<Runnable> shutdownNow() {
return executor.shutdownNow();
}
}
支持JMX管理的Bean,另外为了运维方便,给线程都打上Tag
import java.util.List;
public interface JobHandlerAsyncMBean {
/* 标准MBean条件:MBean接口和实现必须在同一个包下;实现类和MBean接口名称仅仅相差MBean后缀,接口:ABCMBean,那实现类必须是ABC */
String JMX_MBEAN_OBJ_NAME = "com.sohu.tv.live.counter:type=JobHandlerAsync";
/* 第一部分:当前信息部分 */
/** 返回当前有多少个线程正在忙碌地处理报文 */
public int getActiveThreadSize();
/** 返回当前有多少个线程是存活的。注意:存活的(Alive)-忙碌的(Active)=空闲的Idle */
public int getAliveThreadSize();
/** 返回当前队列中积压的作业 */
public int getQueueSize();
/* 第二部分: 统计信息部分 */
/** 返回历史上最高峰值 */
public int getHistoricalPeekThreadSize();
/** 返回累计到现在处理了多少个Job */
public long getHistoricalTotalTaskCount();
/** 返回累计到现在处理成功了多少个Job */
public long getHistoricalCompletedTaskCount();
/* 第三部分: 配置信息部分 */
/** 返回最小设置(初始化不一定能到达最小设置的)*/
public int getCoreThreadSize();
/** 返回最大设置*/
public int getMaxThreadSize();
/** 返回当前队列的最大容量 */
public int getQueueCapacity();
public void shutdown();
public List<Runnable> shutdownNow();
}
import java.lang.management.ManagementFactory;
import javax.management.MBeanServer;
import javax.management.ObjectName;
public class JmxMBeanManager {
private static final Object mbsCreateMonitor = new Object();
private static JmxMBeanManager thisObj;
private final MBeanServer mbs;
public JmxMBeanManager() {
mbs = ManagementFactory.getPlatformMBeanServer();
}
public static JmxMBeanManager getInstance() {
synchronized (mbsCreateMonitor) {
if (null == thisObj) {
thisObj = new JmxMBeanManager();
}
}
return thisObj;
}
public boolean isRegistered(String name) {
try {
ObjectName objName = new ObjectName(name);
return mbs.isRegistered(objName);
}
catch (Exception e) {
throw new RuntimeException("exception while checking if MBean is registered, " + name, e);
}
}
public void registerMBean(Object theBean, String name) {
try {
ObjectName objName = new ObjectName(name);
mbs.registerMBean(theBean, objName);
}
catch (Exception e) {
throw new RuntimeException("exception while registering MBean, " + name, e);
}
}
public void unregisterMBean(String name) {
try {
ObjectName objName = new ObjectName(name);
mbs.unregisterMBean(objName);
}
catch (Exception e) {
throw new RuntimeException("exception while unregistering MBean, " + name, e);
}
}
public Object getAttribute(String objName, String attrName) {
try {
ObjectName on = new ObjectName(objName);
return mbs.getAttribute(on, attrName);
}
catch (Exception e) {
throw new RuntimeException("exception while getting MBean attribute, " + objName + ", " + attrName, e);
}
}
public Integer getIntAttribute(String objName, String attrName) {
return (Integer) getAttribute(objName, attrName);
}
public String getStringAttribute(String objName, String attrName) {
return (String) getAttribute(objName, attrName);
}
}