队列(Queue)
队列是一种特殊的线性表,它只允许在表的后端插入、前端删除。所以队列是先进先出的线性表。你可以把队列看成一个单向管道。
栈(Stack)
栈是一种特殊的线性表,它只允许在标的一端进行插入和删除操作。你可以把栈看作一个凹型容器。
阻塞队列(BlockingQueue)
①支持阻塞的插入方法:意思是当队列满时,队列会阻塞插入元素的线程,直到队列不满。put()。
②支持阻塞的移除方法:意思是在队列为空时,队列会阻塞获取的线程,直到队列变为非空。take()。
除put()、take()方法其他均为非阻塞方法。
应用场景:
阻塞队列一般应用于生产者消费者模式。生产者向队列里添加元素,队列满时阻塞生产者线程、消费者从队列里获取元素,队列为空时阻塞消费者线程。
常用的阻塞队列:(以下队列均实现BlockingQueue接口,是线程安全的)(有界和无界是相对的,并不代表无界就可以一直存储元素,因为内存资源是有限的,所以不可能真正达到无界,无界阻塞队列达到容量后自动扩容)
ArrayBlockingQueue:一个由数组结构组成的阻塞队列。(有界阻塞队列)插入和删除是一把锁,必须指定大小。(常用)
LinkedBlockingQueue:一个由链表结构组成的阻塞队列。(有界阻塞队列)插入putLock,删除takeLock,默认Integer.max。(常用)
PriorityBlockingQueue:一个支持优先级排序的阻塞队列。(无界阻塞队列)默认升序,也可以compareTo()自定义
DelayQueue:一个使用优先级队列实现的阻塞队列。(无界阻塞队列)支持延时获取,队头延迟最长,队尾最短,获取时若时长没到也无法获取。(常用)
SynchronousQueue:一个不存储元素的阻塞队列。(无元素)put阻塞等待take唤醒或者take阻塞等待put唤醒,这样的一个过程称为一次配对过程。
LinkedTransferQueue:一个由链表结构组成的阻塞队列。(无界阻塞队列)transfer异步,等到有消费者消费该元素才返回,trytransfer同步,尝试把该元素给消费者,若有消费者返回true否则false。
LinkedBlockingDeque:一个由链表结构组成的双向阻塞队列。(双向阻塞队列)支持在2端插入和删除。
线程池(ThreadPoolExecutor)
作用:提高响应速度,当任务到达时,可不等待线程的创建就能立即执行。降低资源消耗,能够很好的管理线程。尽量避免创建新线程执行。
使用:
execute()方法用于提交不需要返回值的任务,所以无法判断任务是否被线程池执行成功。
submit()方法用于提交需要返回值的任务。线程池会返回一个future类型的对象,通过这个future对象可以判断任务是否执行成功,并且可以通过future的get()方法来获取返回值,get()方法会阻塞当前线程直到任务完成,而使用get(long timeout,TimeUnit unit)方法则会阻塞当前线程一段时间后立即返回,这时候有可能任务没有执行完。
关闭
调用线程池的shutdown或shutdownNow方法来关闭线程池。
shutdownNow首先将线程池的状态设置成STOP,然后尝试停止所有的正在执行或暂停任务的线程,并返回等待执行任务的列表
shutdown只是将线程池的状态设置成SHUTDOWN状态,然后中断所有没有正在执行任务的线程。
机制:
①如果提交线程时,当前运行的线程<corePoolSize,则创建新线程并执行任务。
②如果提交线程时,当前运行线程已满==corePoolSize,且阻塞队列未满,则进入阻塞队列,等待有空闲线程。
③如果提交线程时,(当前运行线程已满==corePoolSize 且 阻塞队列数已满)运行线程数<maximumPoolSize,则创建新线程执行。
④如果提交线程时,且线程池中运行线程数=maximumPoolSize,则执行RejectedExecutionHandler 参数配置的策略,不配置默认抛出异常。RejectedExecutionHandler出api提供的4种以外, 可自行定义。
线程池的合理配置可以使cpu资源得到合理的分配,主要由于他尽量避免创建新线程来执行,且能够较好的管理线程(因为阻塞队列的机制不同)。
任务特性:
cpu密集型:大量计算。Ncpu+1(maximumPoolSize),+1是防止页缺失情况。
IO密集型:大量IO读取操作(磁盘或网络)。2*Ncpu(maximumPoolSize)
混合型:计算和读取都占有。根据实际情况设定。
拓展:携程,操作系统实际是不支持携程的,携程实际上是线程去分配调度管理多个任务。
网友评论