阻塞队列
add/remove
如果队列满了,add(T)会抛出异常
如果队列为空,remove()会抛出异常
offer/poll
如果队列满了,offer(T)会返回false
如果队列为空,poll()会返回null
put/take
如果队列满了,put(T)会阻塞
如果队列为空,take()会阻塞
常用的阻塞队列
LinkedBlockingQueue:链表实现的阻塞队列,可以不指定大小,默认为Integer.MAX_VALUE
ArrayBlockingQueue:数组实现的阻塞队列,必须指定大小
SynchronousQueue:不能存放元素的阻塞队列
线程池
线程池参数
corePoolSize:核心线程数
maximumPoolSize:最大线程数、规定阻塞队列满了之后,允许创建的最大任务个数
keepAliveTime:线程空闲时间
unit:线程空闲时间单位
workQueue:阻塞队列
threadFactory:线程工厂,主要是给线程指定name
handler:拒绝策略,默认是抛出异常
AbortPolicy:当任务书大于maximumPoolSize+阻塞队列大小之后,会抛出异常
DiscardPolicy:抛弃最近提交的任务
DiscardOldestPolicy:抛弃最早提交未执行的任务
CallerRunsPolicy:由调用线程自己执行该任务,如果是主线程那么就是main
线程池工作原理
· 提交的任务数小于等于核心线程数,会创建核心线程执行任务
·提交的任务数大于核心线程数,超出部分会被加入阻塞队列中
·阻塞队列如果满了,判断超出的任务数是否大于最大线程数,如果大于那么走拒绝策略,否则执行。
合理配置线程池
CPU密集型
有大量计算型的任务,最大线程数不要超过逻辑核心数
IO密集型
有大量磁盘io,网络通讯,最大线程数一般配置为2*逻辑核心数
线程不安全的原因
java内存模型中,为了提高效率在线程中引入了工作内存和主存,工作内存是线程私有的,两个线程同时要修改一个变量,刚开始都是从主存中拷贝一份副本,然后在工作内存中修改值,在未来某个时间刷新到主存中,由于两个线程都是在自己内部的工作内存修改变量,所以最终刷新到主存中的数据可能是不正确的,这就是线程不安全的原因。