线程的中断
使用线程的interrupt(),正在wait,sleep,yield的线程会抛出InterruptedException,退出sleep;
线程池超过核心线程数是如何退出的
线程池没有核心线程和非核心线程之说,只是记录了创建的线程数量。
- 线程池线程在等待任务时是靠的阻塞队列,阻塞队列为空会阻塞,有任务才会拿到任务执行
- 当线程数超过核心线程数,或者线程池允许核心线程过期的话,采用阻塞队列的poll(allowTimeout,)方法进行超时等待,靠的是Condition的awaitNanos进行有限的等待;小于核心线程数就采用永久阻塞的take()方法获取任务。
- 超时没有获取到任务,线程就会退出;
线程池的关闭
主要是依靠中断标志位
如果是interupt,则会拒绝新任务提交,等待全部任务执行完毕才会关闭
如果是interuptNow,则会直接放弃所有阻塞队列中的任务,在工作的线程等待任务结束之后就结束。
阻塞队列
区别
- ArrayBlockingQueue:内部是Object数组,有界,使用一个ReentrantLock的两个Condition来维护读和写
- LinkedBlockingQueue:内部是单向链表,有界,使用两个ReentrantLock来分别维护读和写,锁的粒度更小
- LinkedBlockingDeque:双向链表,有界,使用一个ReentrantLock控制并发,一般用于”工作窃取”模式;
- PriorityBockingQueue:内部是数组实现的队列,无界(不够时会扩容),提供排序功能,只有一个reentrantLock锁和一个Condition实现(用于通知消费)
- DelayQueue:组合了一个PriorityQueue,无界,先按延迟优先级排序,延迟时间短的排前面,取出任务前要判断是否已经到达延时时间。采用一个RenentrantLock和一个Condition控制并发,常用于执行定时任务。
- SynchronousQueue:没有容量,不会存储数据。不使用锁,全部使用CAS操作实现并发,自旋失败会通过LockSupport.park将线程挂起。用于处理高效的传递性场景;
- LinkedTransferQueue:内部是链表实现的,无界,阻塞队列。内部采用大量CAS操作,put操作不会阻塞,只有take时可能阻塞消费线程,同样用park方法挂起。
有界阻塞队列包括:ArrayBlockingQueue、LinkedBlockingQueue以及LinkedBlockingDeque三种,LinkedBlockingDeque应用场景很少,一般用在“工作窃取”模式下。ArrayBlockingQueue和LinkedBlockingQueue基本就是数组和链表的区别。 无界队列包括PriorityBlockingQueue、DelayQueue和LinkedTransferQueue。PriorityBlockingQueue用在需要排序的队列中。DelayQueue可以用来做一些定时任务或者缓存过期的场景。LinkedTransferQueue则相比较其他队列多了transfer功能。 最后剩下一个不存储元素的队列SynchronousQueue,用来处理一些高效的传递性场景。
疑问
volatile禁止指令重排序