学习自1小时搞清楚Java线程池原理
线程是我们调度cpu的最小单元,
用户级线程ULT:就是由我们电脑安装的第三方应用来创建和管理的,不需要用户态、内核态之间切换,速度快,内核对ult是无感知的
内核级线程KLT:操作系统管理和创建
最主要的区别:就是ULT是由我们第三方应用app创建管理,而KLT是我们操作系统os来创建管理。
JVM使用的是哪一种线程模型呢?
如果是ULT的话,我们Java创建多个线程,任务管理器应该看不到变化,而如果是KLT,应该能看到明显的变化
创建300个线程后,这个数变成了3500左右,虽然Java规范中没有说使用ULT或者KLT,但是目前市场上大部分JVM都使用KLT。
如果我们硬件是8G,我们的操作系统会把这个物理空间转化为逻辑空间,
这个逻辑空间一般比物理空间小一点点,会分为用户空间和内核空间,他们俩的权限级别不一样,内核空间只有我们的操作系统内核能访问,第三方app只能运行在用户空间中,例如我们的qq,JVM,那我们的JVM是怎么访问内核空间来创建线程呢,一般我们的内核系统都会开放一个创建线程的API(linux是p_thread),创建的线程再映射到我们底层的CPU
线程池的意义
线程是稀缺资源,他的创建和销毁是一个相对偏重而且消耗资源的过程,而Java线程依赖内核线程,创建线程需要进行操作系统的切换,为了避免资源的过度消耗,我们尽可能的重用线程来执行任务,线程池就能实现对线程的分配,调优和控制。
线程池的优点:
1)节约资源
2)提高响应速度,任务不需要等待线程的创建
3)提高线程的可管理性,可分配性
什么时候适合使用线程池?
1)单个任务处理时间短
2)任务量又比较大
Executors 是Java的一个创建线程池的工具类,里面封装了几种常用的线程池
corePoolSize:核心线程大小,正式公
maximumPoolSize:线程池最大能创建多少个线程,超过核心线程数量的可以看做是临时工
keepAliveTime:线程最多可以空闲多久,比如说60,即临时工在60时间内没有干活的话就会被解聘
Queue:阻塞队列,线程池的线程都在执行任务时,再有任务就存在queue中,在任何时候,无论并发有多高,永远只有一个线程能够进行队列的入队和出队操作。队列分有界和无界(受限于我们内存大小),队列满了,只能进行出队操作,所有入队的操作必须等待,这个ArrayBlockingQueue底层基于数组
线程池执行的任务必须实现runnable接口
1)线程池刚初始化的时候里面是没有线程的,线程数为0
2)如果任务数超过核心线程数了,新的任务就会去阻塞队列
3)如果阻塞队列也满了,才会去找临时工
4)正式工和临时工都满了,队列也满了,就会执行拒绝策略(默认1,抛异常2直接执行被拒绝的任务3抛弃最老的任务,并尝试再次提交当前任务4直接拒绝
线程池并不一定能够保证任务执行的顺序。
比如上面的那个例子,给他9个任务,两个正式工会先执行0和1号任务,然后2,3,4,5,6号任务存入队列,然后临时工执行7号任务