阻塞队列BlockingQueue
阻塞队列常用于生产者——消费者模型,生产者往阻塞队列插入数据,消费者往阻塞队列获取数据;阻塞队列常见的触发场景:当队列没有数据时,消费端的所有线程被阻塞;当队列数据满了时,生产端的所有线程被阻塞。
接口BlockingQueue只要定义两种操作:出队和入队;
(1)入队:
offer()往队列中插入数据,如果队列容量允许的话返回true,否则返回false,不会产生阻塞;
put()往队列插入数据,如果队列空间满了将产生阻塞直到有空间为止;
(2)出队:
poll()往队列中获取排在首位的数据,如果获取成功返回true,否则一段时间内获取不到返回false,不会产生阻塞;
take()往队列中获取排在首位的数据,如果队列为空则产生阻塞直到有新的数据加入;
常见的两种阻塞队列:
(1)ArrayBlockingQueue:阻塞锁是非独立的,即添加操作和移除操作采用的同一个ReenterLock锁;当队列可用时会公平的阻塞生产者和消费者的线程,然后按照阻塞的先后顺序访问队列;也就是说先阻塞的生产者线程,可以先往队列中插入元素,先阻塞的消费者线程,可以先往队列中获取元素。(为了保证公平使得并发性能下降)
(2)LinkedBlockingQueue:阻塞锁是独立的,即生产者和消费者分别采用了独立的锁来插入和读取;也就是说在高并发的情况下生产者和消费者可以并发地操作队列中的数据;但是会产生一种情况就是当构造LinkedBlockingQueue对象时没有指定容量大小的话,系统会默认分配无限大小的容量,这时候如果生产者的速度大于消费者的速度,也许还没有等到队列满阻塞,系统内存就有可能耗尽了。(并发性能高)
线程池
1、线程池的优点
(1)重用线程池中的线程,避免因频繁创建和销毁线程所带来的系统开销;
(2)能有效控制线程池的最大并发数,避免大量的线程因互相抢占系统资源而导致的阻塞现象;
(3)能对线程进行简单的管理,并提供定时执行以及指定间隔时间循环执行等功能;
2、线程池的几个重要参数
(1)corePoolSize:核心线程数;默认情况下线程池是空的,当有任务提交时才会创建线程进行处理,当线程数小于corePoolSize,则创建核心线程处理任务;当线程数等于大于corePoolSize,不再创建核心线程,而是把任务加入阻塞队列中;核心线程一旦创建就会默认一直存活于线程池中,即使他们处于闲置状态。
(2)maximumPoolSize:线程池允许创建的最大线程数;当线程数超过maximumPoolSize时,后续任务将会被阻塞。
(3)keepAliveTime:非核心线程的闲置超时时间;当超过该闲置时间,非核心线程将会被回收。(也可以通过设置ThreadPoolExecutor.allowCoreThreadTimeOut为true来作用于核心线程)
(4)workQueue:任务队列(BlockingQueue);只有当线程数超过核心线程数才会将任务加入任务队列中。
(5)饱和策略:当线程池中的线程数超过最大线程数时会执行饱和策略,一般是抛出RejectedExecutionException异常。
3、线程池的工作流程
线程池的处理流程(1)如果线程池中的线程数未超过corePoolSize,则创建核心线程处理任务;
(2)如果线程数超过corePoolSize,则把任务加入到阻塞队列中,等待空闲的核心线程来处理;
(3)如果阻塞队列已满,则判断线程数是否超过maximumPoolSize,如果未超过则创建新的非核心线程处理任务;
(4)如果线程数超过maximumPoolSize,则执行饱和策略;
4、线程池的种类
(1)FixedThreadPool:固定核心线程数的线程池。使用固定的核心线程数,没有非核心线程,使用LinkedBlockingQueue阻塞队列;当核心线程处于空闲状态时,它们并不会被回收,除非线程池关闭了,当核心线程处于非闲置状态,任务队列被阻塞直到有空闲的线程来处理;(由于核心线程不会被回收所以可以更加快速地处理任务)
FixedThreadPool(2)CachedThreadPool:只有非核心线程的线程池。无核心线程,非核心线程数无限大,有线程闲置超时时间,使用SynchronousQueue阻塞队列;由于没有非核心线程数量的限制,所以一旦有任务提交时就会创建新的非核心线程进行处理,如果线程池中空闲的线程并且闲置时间超过60s,就会被系统回收,所以这样相当于SynchronousQueue阻塞没有存储过任务,可以理解为无法存储元素的队列;(适用于处理大量的耗时少的任务,几乎不占用系统资源)
CachedThreadPool(3)ScheduledThreadPoolExecutor:固定核心线程数,无限制的非核心线程数,有超时时间,DelayedWorkQueue阻塞队列;这类线程主要用于执行定时任务和具有固定周期的重复任务;
ScheduledThreadPoolExecutor(4)SingleThreadExecutor:只有一个核心线程的线程池;
SingleThreadExecutor参考:
《Android进阶之光》 第4章 多线程编程
《Android开发进阶:从小工到专家》 第3章 3.2 Android的多线程
《Android开发艺术探索》第11章 Android中的线程和线程池
网友评论