阅读了阿里JAVA开发手册泰山版,其中关于线程池的创建有个强制要求:线程池不允许使用Executors去创建,而是通过ThreadPoolExecutor的方式,这 样的处理方式更加明确线程池的运行规则,规避资源耗尽的风险。
说明:Executors返回的线程池对象的弊端如下:
1)FixedThreadPool和SingtelThreadPool
允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM。
2)CachedThreadPool
允许的创建线程数量为 Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM。
下面看看使用Executors创建线程的方式
1.创建CachedThreadPool
1.1 使用Executors创建
ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();
Executors的newCachedThreadPool()方法
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
newCachedThreadPool()方法的第二个参数是线程池允许的最大线程数,使用该方法创建的线程池默认使用Integer.MAX_VALUE作为线程池允许的最大线程数。所以使用该线程池时可能会创建大量的线程,从而导致内存溢出。
1.2 使用ThreadPoolExecutor,自定义参数创建
ThreadPoolExecutor cacheThreadPool = new ThreadPoolExecutor(10, 100, 60L,
TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(true));
构建SynchronousQueue的参数fair表示创建的同步队列是公平的还是不公平的,true则使用FIFO规则的队列(Queue),false则使用栈(Stack)
public SynchronousQueue(boolean fair) {
transferer = fair ? new TransferQueue<E>() : new TransferStack<E>();
}
2. 创建FixedThreadPool
2.1 使用Executors创建
ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(10);
Executors的newFixedThreadPool()方法
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
public LinkedBlockingQueue() {
this(Integer.MAX_VALUE);
}
public LinkedBlockingQueue(int capacity) {
if (capacity <= 0) throw new IllegalArgumentException();
this.capacity = capacity;
last = head = new Node<E>(null);
}
LinkedBlockingQueue默认创建的队列没有指定任务队列的容量,使用默认容量Integer.MAX_VALUE,因此可能会堆积大量的任务,导致内存溢出。
同理SingleThreadExecutor。
3. ThreadPoolExecutor submit()和execute()执行任务的区别
- submit()方法是ThreadPoolExecutor父类AbstractExecutorService中实现的, 最后都会调用到AbstractExecutorService的实现类中的execute()方法。
- execute()方法是ThreadPoolExecutor实现的。
- submit()有返回值 Future,所以submit()方法执行任务是异步的。
- execute()没有返回值,不是异步的。
AbstractExecutorService中的submit()方法
public Future<?> submit(Runnable task) {
if (task == null) throw new NullPointerException();
RunnableFuture<Void> ftask = newTaskFor(task, null);
execute(ftask); // execute()在子类中实现
return ftask;
}
ThreadPoolExecutor中实现的execute()方法
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
int c = ctl.get();
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command))
reject(command);
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
else if (!addWorker(command, false))
reject(command);
}
仅供参考
关于阿里JAVA开发手册泰山版,详情点击这里免费下载。
说明:下载的手册不得用作任何商业意图,否则将依法追究相关法律责任,谨记。
如有侵权,请联系博主。