目录
一、并发:线程状态
java的线程状态分为六种
-
新建 NEW
-
当一个线程对象被创建,但是还没有调用start方法时处于新建状态
-
此时未与操作系统底层线程关联
-
-
可运行 RUNNABLE
-
调用了start方法,就会由新建进入可运行状态
-
此时与底层线程关联,由操作系统调度执行
-
(可以细分为准备和运行)准备就是进入了可以得到cpu,但是还没有得到cpu时间片
-
运行就是得到cpu时间片正在执行代码
-
-
终结 TERMINATED
-
线程内代码执行完毕,由可运行进入终结
-
此时会取消与底层线程关联
-
-
阻塞 BLOCKED
-
当获取锁失败后,由可运行状态进入阻塞,此时不占用cpu时间
-
当锁释放后,会按照一定规则唤醒阻塞队列中阻塞的多个线程,重新获取锁
-
得到锁的线程进入可运行状态, 没有得到锁的进入阻塞状态
-
-
等待 WAITING
-
当获取锁成功后,由于条件不满足,调用Object对象的wait()方法,释放锁,此时从可运行状态进入到等待状态,同样不扎弄cpu时间
-
当其他锁线程调用notify()或notifyAll()方法,会按照一定规则唤醒等待集合中党的线程,然后获取锁,
-
如果没有获取到就进入阻塞状态,如果获取到锁就进入可运行状态
-
-
有时限等待 TIME_WAITING
-
当获取锁成功后,但由于条件不满足,调用wait(long) 方法,此时从可运行状态释放锁进入 有时限等待状态,同样不占用cpu
-
当其他持有锁的线程调用当其他锁线程调用notify()或notifyAll()方法,会按照一定规则唤醒等待集合中的线程,然后获取锁,如果没有获取到就进入阻塞状态,如果获取到锁就进入可运行状态
-
如果等待超时,也会从有时限的等待状态到可运行状态,重新去竞争锁
-
还有一种情况是,调用线程的sleep(long) 方法也会从可运行状态进入有时限等待状态,这个时候没有释放锁,不需要主动唤醒,超过时间自动恢复为可运行状态
-
五种状态的说法来自于操作系统层面的划分
-
运行态:分到 cpu 时间,能真正执行线程内代码的
-
就绪态:有资格分到 cpu 时间,但还未轮到它的
-
阻塞态:没资格分到 cpu 时间的
-
涵盖了 java 状态中提到的阻塞、等待、有时限等待
-
多出了阻塞 I/O(java中阻塞I/O是在可运行状态中包含),指线程在调用阻塞 I/O 时,实际干活由 I/O 设备完成,此时线程无事可做,只能干等
-
新建与终结态:与 java 中同名状态类似
二、线程池的核心参数
核心线程:当任务来的时候执行,执行完毕后核心线程也不会被销毁
救急线程:当任务来的时候执行,执行完毕后根据keepAliveTime生存时间和unit时间单位,时间一过就进行销毁
执行的流程:
- 当核心线程空闲的时候,加入任务,核心线程就进行执行
- 当核心线程全部工作的时候,阻塞队列还有位置的情况下,加入任务后,就直接加入到阻塞队列中
- 当核心线程全部工作,阻塞队列的位置也满的时候,这个时候如果有救急线程空闲,救急线程就进行执行
- 当核心线程全部工作,阻塞队列位置也满的时候,救急线程也全部在工作,这个时候就按照四种拒绝策略进行执行
三、sleep和wait的区别和联系
共同点
wait(),wait(long),sleep(long)的效果都是让当前线程暂时放弃cpu的使用权,进入阻塞状态
不同点
方法归属不同:
1.sleep(long)是Thread的形态方法
2.wait(),wait(long)都是Object的成员方法,每个对象都有
醒来时机不同
1.执行sleep(long)和wait(long)的线程都是在等待响应毫秒后自动醒来
2.wait(long),wait()还可以被notify(),notifyAll()唤醒,其中notify()是随机进行唤醒,wait()如果不唤醒就一直等下
3.它们都可以被打断唤醒 ---线程.interrupt(),调用后打断唤醒,然后抛出异常
锁特性不同
1.wait()方法的调用必须西安获取wait对象的锁(即必须在synchronized代码块中执行),而sleep则无此限制
2.wait方法执行后会执行对象锁,允许其他线程获取该对象的锁
3.sleep如果在synchronized中执行,并不会释放锁