一、JDK底层给我们提供了哪些常用的创建线程池的方法?
JDK主要是通过Executors工具类来创建线程池方法
1.newFixedThreadPool(int Thread) 创建固定线程数的线程池
底层实现:
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue());
}
2.newCacheThreadPool() 创建可缓存的线程池,如果线程池中有可用的线程则复用,没有的话就一直创建线程
底层实现:
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, 2147483647, 60L, TimeUnit.SECONDS, new SynchronousQueue());
}
3.newSingleThreadPool() 创建一个单线程的线程池
底层实现:
public static ExecutorService newSingleThreadExecutor() {
return new Executors.FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue()));
}
4.newScheduledThreadPool(int corePoolSize) 创建一个支持定时及周期性的任务执行的线程池,可代替用Timer定时器类
底层实现:
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, 2147483647, 10L, TimeUnit.MILLISECONDS, new ScheduledThreadPoolExecutor.DelayedWorkQueue());
}
二、为什么在开发的时候不建议使用这几种线程池创建?
1.newFixedThreadPool和newSingleThreadPool在底层的实现上面用的阻塞队列是LinkedBlockingQueue实现的,在未指定初始化的大小时,默认是Integer.MAX_VALUE,大约是2的31次方,导致允许的队列太长,请求大量的堆积,从而导致OOM
2.newCacheThread和newScheduleThreadPool允许创建的最大线程数量为Integer.MAX_VALUE,可能导致无限的创建线程,导致资源耗尽,从而OOM.
三、阻塞队列的种类和选择?
1.ArrayBlockingQueue 有界队列
内部是用数组存储元素的,底层是通过ReentrantLock实现的线程安全,在创建它的时候需要指定容量,之后也不可以在扩容,在构造函数中我们可以指定是否公平:ArrayBlockingQueue(int capacity, boolean fair)
第一个参数是容量,第二个参数是否公平。如果设置非公平那么就有可能存在插队的可能,设置公平的话,按FIFO的方式获取线程资源,其他的线程不允许插队。
2.LinkedBlockindQueue 有界对列
内部是用链表实现的,如果我们不指定大小,默认是Integer.MAX_VALUE,由于是非常大,这种场景下可以作为无界队列使用。
3.SynchronusQueue 相当于有界队列
内部的容量是0, SynchronousQueue 不需要去持有元素,它所做的就是直接传递(direct handoff)。由于每当需要传递的时候,SynchronousQueue 会把元素直接从生产者传给消费者,在此期间并不需要做存储,所以如果运用得当,它的效率是很高的
4.PriorityBlockingQueue 无界队列
ArrayBlockingQueue 和 LinkedBlockingQueue 都是采用先进先出的顺序进行排序,可是如果有的时候我们需要自定义排序怎么办呢?这时就需要使用 PriorityBlockingQueue无界队列,而且会自动扩容.
PriorityBlockingQueue 是一个支持优先级的无界阻塞队列,可以通过自定义类实现 compareTo() 方法来指定元素排序规则,或者初始化时通过构造器参数 Comparator 来指定排序规则。
5.DelayQueue 无界队列
DelayQueue这个队列具有延迟的功能,我们可以设定队列中的任务延迟多久之后执行,例如10s后执行,或者30分钟后未付款自动取消订单等需要延迟执行的场景中大量使用,它是无界队列,放入的元素必须实现 Delayed 接口,而 Delayed 接口又继承了 Comparable 接口,所以自然就拥有了比较和排序的能力,代码如下
public interface Delayed extends Comparable {
long getDelay(TimeUnit unit);
}
可以看出这个 Delayed 接口继承自 Comparable,里面有一个需要实现的方法,就是 getDelay。这里的 getDelay 方法返回的是“还剩下多长的延迟时间才会被执行”,如果返回 0 或者负数则代表任务已过期
元素会根据延迟时间的长短被放到队列的不同位置,越靠近队列头代表越早过期。
DelayQueue 内部使用了 PriorityQueue 的能力来进行排序
限 时 特 惠: 本站每日持续更新海量各大内部创业教程,一年会员只需98元,全站资源免费下载 点击查看详情
站 长 微 信: lzxmw777