客户端使用,代码清洁,装饰器模式

 

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);
    }
}