从java5开始,java官方推荐我们使用并发包下的Executors来处理多线程;
Executors下面一共给我们提供了4种类型的线程池:
1:固定长度的线程池
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue());
}
先看下官方注释:
创建一个线程池,该线程池重用固定数量的线程操作一个共享的无界队列。在任何时候,你的线程数都不会超过你设定的线程池的大小,如果所有的线程都处于活动状态,这时候如果有新任务提交,则会进入队列中等待,直到有任务释放线程,如果有线程由于失败终止,那么会另外开辟一个线程来替代原来失败的线程。
另外最重要的一点,这个线程池中的线程不会自动关闭,需要你手动关闭。
2: 单一线程池
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue()));
}
这个就是创建一个单一的线程执行任务,如果这个单线程在执行之前由于失败而终止,则会有一个新的线程取代它执行后续任务,来保证任务的顺序执行;
3:缓冲线程池
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue());
}
缓冲线程池是可以动态创建的,每来一个任务就会开辟一个线程,如果之前开辟的线程任务执行完,这这个释放的线程又可以用来执行新的任务,理论上可以创建2的29次方个线程(java中设置了32位的值,后4位标识线程状态,前29位记录线程数量)。
当一个线程超过60秒的未使用,则该线程将被终止并从缓存中删除。因此,一个空闲时间足够长的池不会消耗任何资源。
4:定时线程
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
创建一个线程池,该线程池可以调度在之后运行的命令来延迟执行,或周期性执行。
同样的你设定的corePoolSize这些线程不会自动回收,会一直存在内存中。
好了,下面介绍下自己遇到的一个小问题,其实是因为粗心,没有注意,因为我这个业务是周期执行;所以,在程序中我手动执行了shutdown()方法,而导致了错误,首先看下我自己定义的线程池类;
public enum ThreadPoolUtil {
INSTANCE;
private ExecutorService newCachedThreadPool = null;
private ThreadPoolUtil () {
newCachedThreadPool = Executors.newCachedThreadPool();
}
public ExecutorService getInstance() {
return newCachedThreadPool;
}
}
这里我用的是缓存线程池;
业务代码大概是这样
List newtLst = paymentPlanRstList.subList(i, i + toIndex);
Future> future = threadPool.submit(new Callable>() {
@Override
public Set call() {
return kingdeePmentPlanSync(newtLst, succCnt, failCnt);
}
});
futures.add(future);
这是调用业务的代码段,但是问题就出在下面这个地方:
}finally {
//关闭线程池
// threadPool.shutdown();
}
我在try catch的finally手动关闭了线程池,第一次执行没有问题,当下一次轮询的时候,由于我已经把线程池关闭,导致后续的线程添加不进来,然后报了RejectedExecutionException 拒绝异常;
因为我用的是缓存线程池,其实就算不关闭,jvm也会在任务执行完后60自动帮我们关闭。
大概就是这个情况,mark一下;防止再犯;