2018-06-14: Java 定时任务线程池 ExecutorService 使用总结

一、背景:
重构了一个项目,将之前散乱的多线程和定时任务线程作统一管理,减小代码量并提高代码可读性。java

二、直接上代码 - 可直接COPY使用 ----------------------------缓存

-、新建一个线程池构造工厂类 ExecutorServiceFactory:安全

package com.aaa.bbb.ccc.ddd;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;

/**
* @Function : 线程池构造工厂
* @Author & @Date : lynn_ - 2018年6月14日
*/
public class ExecutorServiceFactory {

// 实例化ExecutorServiceFactory
private static ExecutorServiceFactory executorServiceFactory = new ExecutorServiceFactory();

// 定时任务线程池
private ExecutorService executorService;

/**
 * 默认无参构造
 */
private ExecutorServiceFactory() { }

/**
 * @Function: 获取ExecutorServiceFactory
 */
public static ExecutorServiceFactory getInstance() {
	return executorServiceFactory;
}

/**
 * @Function: 建立一个定长的线程池 - 它可安排在给定延迟后运行命令或者按期地执行
 */
public ExecutorService createScheduledThreadPool() {
	// CPU个数
	int availableProcessors = Runtime.getRuntime().availableProcessors();
	// 建立
	executorService = Executors.newScheduledThreadPool(availableProcessors * 10, getThreadFactory());
	return executorService;
}

/**
 * @Function: 建立一个单线程化的Executor,即只建立惟一的工做者线程来执行任务,它只会用惟一的工做线程来执行任务,保证全部任务按照指定顺序(FIFO, LIFO, 优先级)执行
 *            Executor,以无界队列方式来运行该线程。(注意,若是由于在关闭前的执行期间出现失败而终止了此单个线程,
 *            那么若是须要,一个新线程将代替它执行后续的任务 )。可保证顺序地执行各个任务,
 *            而且在任意给定的时间不会有多个线程是活动的。与其余等效的 newFixedThreadPool(1)
 *            不一样,可保证无需从新配置此方法所返回的执行程序便可使用其余的线程。
 */
public ExecutorService createSingleThreadExecutor() {
	// 建立
	executorService = Executors.newSingleThreadExecutor(getThreadFactory());
	return executorService;
}

/**
 * @Function: 建立一个可缓存线程池,若是线程池长度超过处理须要,可灵活回收空闲线程,若无可回收,则新建线程
 *            对于执行不少短时间异步任务的程序而言,这些线程池一般可提升程序性能。调用 execute将重用之前构造的线程(若是线程可用)。
 *            若是现有线程没有可用的,则建立一个新线程并添加到池中。 终止并从缓存中移除那些已有 60 秒钟未被使用的线程。
 *            所以,长时间保持空闲的线程池不会使用任何资源。注意,可使用 ThreadPoolExecutor
 *            构造方法建立具备相似属性但细节不一样(例如超时参数)的线程池。
 */
public ExecutorService createCachedThreadPool() {
	// 建立
	executorService = Executors.newCachedThreadPool(getThreadFactory());
	return executorService;
}

/**
 * @Function: 建立一个指定工做线程数量的线程池。每当提交一个任务就建立一个工做线程,
 *            若是工做线程数量达到线程池初始的最大数,则将提交的任务存入到池队列中。
 *            可重用固定线程数的线程池,以共享的无界队列方式来运行这些线程。在任意点,在大多数 nThreads
 *            线程会处于处理任务的活动状态。若是在全部线程处于活动状态时提交附加任务,则在有可用线程以前,附加任务将在队列中等待。
 *            若是在关闭前的执行期间因为失败而致使任何线程终止,那么一个新线程将代替它执行后续的任务(若是须要)。
 *            在某个线程被显式地关闭以前,池中的线程将一直存在。
 */
public ExecutorService createFixedThreadPool(int count) {
	// 建立
	executorService = Executors.newFixedThreadPool(count, getThreadFactory());
	return executorService;
}

/**
 * @Function: 获取线程池工厂
 */
private ThreadFactory getThreadFactory() {
    return new ThreadFactory() {
        // AtomicInteger是一个提供原子操做的Integer类,经过线程安全的方式操做加减
        AtomicInteger sn = new AtomicInteger();

    	@Override
    	public Thread newThread(Runnable r) {
    		// 安全管理器
    		SecurityManager s = System.getSecurityManager();
    		// 全部线程都隶属于一个线程组
    		ThreadGroup group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup();
    		Thread t = new Thread(group, r);
    		t.setName("任务线程 - " + sn.incrementAndGet());
    		return t;
    	}
	};
}
}
复制代码

--、新建一个线程处理类 ExecutorProcessPool:多线程

package com.aaa.bbb.ccc.ddd;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;

/** 
* @Function :  线程处理类
* @Author & @Date : lin.li  - 2018年6月14日 
*/ 
public class ExecutorProcessPool {

//线程池接口
private ExecutorService executor;
//实例化当前类
private static ExecutorProcessPool pool = new ExecutorProcessPool();

/**
 * Creates a new instance of ExecutorProcessPool
 */
private ExecutorProcessPool() {
    executor = ExecutorServiceFactory.getInstance().createCachedThreadPool();
}

/**
 * @Function: 获取 ExecutorProcessPool
 */
public static ExecutorProcessPool getInstance() {
    return pool;
}

/**
 * @Function:  关闭线程池,这里要说明的是:调用关闭线程池方法后,线程池会执行完队列中的全部任务才退出
 */
public void shutdown(){
    executor.shutdown();
}

/**
 * @Function: 提交任务到线程池,能够接收线程返回值 - Future模式
 */
public Future<?> submit(Runnable task) {
    return executor.submit(task);
}
public Future<?> submit(Callable<?> task) {
    return executor.submit(task);
}

/**
 * @Function: 直接提交任务到线程池,无返回值
 */
public void execute(Runnable task){
    executor.execute(task);
}
}
复制代码

---、核心代码就这点了,下面是测试类 ExecutorTest:dom

package com.goldpac.ito.system.interceptor;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

/**
* @Function : 线程池测试类
* @Author & @Date : lin.li - 2018年6月11日
*/
public class ExecutorTest {

public static void main(String[] args) {
    //获取实例
    ExecutorProcessPool pool = ExecutorProcessPool.getInstance();

    //for循环添加多个线程 - 
    for (int i = 0; i < 200; i++) {
        Future<?> future = pool.submit(new ExcuteTask1(i + ""));
        try {
            //若是接收线程返回值,future.get() 会阻塞,若是这样写就是一个线程一个线程执行。因此非特殊状况不建议使用接收返回值的。
            System.out.println(future.get());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //没有返回值。能够执行任务,但没法判断任务是否成功完成。
    //execute(Runnable x);
	
    //for (int i = 0; i < 200; i++) {
    //  pool.execute(new ExcuteTask2(i + ""));
    //}

    // 关闭线程池,若是是须要长期运行的线程池,不用调用该方法。
    // 监听程序退出的时候最好执行一下。
    pool.shutdown();
}

/**
 * 执行任务1,实现Callable方式
 */
static class ExcuteTask1 implements Callable<String> {
	private String taskName;

	public ExcuteTask1(String taskName) {
		this.taskName = taskName;
	}

	@Override
	public String call() throws Exception {
		try {
			// Java 6/7最佳的休眠方法为TimeUnit.MILLISECONDS.sleep(100);
			// 最好不要用 Thread.sleep(100);
			// 1000毫秒之内的随机数,模拟业务逻辑处理
			TimeUnit.MILLISECONDS.sleep((int) (Math.random() * 1000));
		} catch (Exception e) {
			e.printStackTrace();
		}
		System.out.println("-------------这里执行业务逻辑,Callable TaskName = " + taskName + "-------------");
		return ">>>>>>>>>>>>>线程返回值,Callable TaskName = " + taskName + "<<<<<<<<<<<<<<";
	}
}

/**
 * 执行任务2,实现Runable方式
 */
static class ExcuteTask2 implements Runnable {
	private String taskName;
	public ExcuteTask2(String taskName) {
		this.taskName = taskName;
	}
	@Override
	public void run() {
		try {
			// 1000毫秒之内的随机数,模拟业务逻辑处理
			TimeUnit.MILLISECONDS.sleep((int) (Math.random() * 1000));
		} catch (Exception e) {
			e.printStackTrace();
		}
		System.out.println("-------------这里执行业务逻辑,Runnable TaskName = " + taskName + "-------------");
	}
}
}复制代码
相关文章
相关标签/搜索