使用线程池来创建线程
1.如何使用线程池来创建线程?
java中提供了一个静态工厂方法来创建不同的线程池: Executors
通过静态方法创建出的线程都实现了ExecutorService接口。常用的方法包括:
newFixedThreadPool(int threads); 创建一个固定数目的线程池
newCachedThreadPool(); 创建一个可缓存的线程池,调用execute方法将重用以前创建的线程,如果没有可用线程则创建一个新的线程并添加到池中。终止并移除那些已经存在60s未被使用的线程。
newSingleThreadPoolExcutor() 创建一个单线程化的Excutor
newScheduledThreadPool(int corePoolSize) 创建一个定时及周期性执行任务的线程池。
2. 为什么不推荐使用jdk自带的executors的方式来创建线程池?
在阿里巴巴java开发手册中明确规定不允许使用Executors创建线程池。
查看JDK源码:
可以看到实现是实例化一个ThreadPoolExecutor,创建的阻塞队列为new LinkedBlockQueue。
java中的阻塞队列有两种 ArrayBlockingQueue LinkedBlockingQueue.
ArrayBlockingQueue是一个以数组设计的有界队列,必须设置大小
LinkedBlockingQueue 是一个以链表实现的有界阻塞队列,容量可以选择设置,不设置的话是无界的最大长度为Integer.MAX_VALUE。
所以说Executors创建线程池没有传入阻塞队列的长度,阻塞队列就是一个无边界队列,对于一个无边界队列来说是可以向其中无限添加任务的,这种情况下可能由于任务数太多而导致内存溢出。
FixedThreadPool和SingleThreadPool允许等待的请求队列是Integer.MAX_VALUE 可能导致内存溢出。 而CachedThreadPool和shceduledThreadPool允许创建的线程数量是Integer.MAX_VALUE 同样会出现内存溢出。
创建线程池的正确方式:
避免使用Executors创建线程池主要是为了避免其中的默认实现,可以改用ThreadPoolExecutor构造方法指定参数即可。
需要指定核心线程池的大小、最大线程池的数量、保持存活的时间、等待队列容量的大小。在这种情况下一旦提交的线程数超过当前可用的线程数时就会抛出拒绝执行的异常 java.util.concurrent.RejectedExecutionException 有界队列已经满了便无法处理新的任务。
使用工具类来创建线程池:
除了自己定义的ThreadPool之外,还可以使用开源库 apache guava等。
个人推荐使用guava的ThreadFactoryBuilder() 来创建线程池:
使用上面的方法创建线程池不仅可以避免OOM的问题,还可以自定义线程名称,更加方便出错时溯源。
原文出处:
csdn_wangchen, 使用线程池来创建线程, https://blog.csdn.net/csdn_wangchen/article/details/84629088