线程的生命周期
初始状态(NEW)
指的是线程已经被创建,但是还不允许分配 CPU 执行
可运行状态(RUNNABLE)
指的是线程可以分配 CPU 执行
运行状态(RUNNABLE)
当有空闲的 CPU 时,操作系统会将其分配给一个处于可运行状态的线程,被分配到 CPU 的线程的状态就转换成了运行状态
休眠状态(WAITING/TIMED_WAITING)
运行状态的线程如果调用一个阻塞的 API(例如以阻塞方式读文件)或者等待某个事件(例如条件变量),那么线程的状态就会转换到休眠状态
终止状态(TERMINATED)
线程执行完或者出现异常就会进入终止状态
线程间状态的转换
RUNNABLE 与 BLOCKED 的状态转换
synchronized 的隐式锁
RUNNABLE 与 WAITING 的状态转换
第一种场景,获得 synchronized 隐式锁的线程,调用无参数的 Object.wait() 方法
第二种场景,调用无参数的 Thread.join() 方法
第三种场景,调用 LockSupport.park() 方法
RUNNABLE 与 TIMED_WAITING 的状态转换
调用带超时参数的 Thread.sleep(long millis) 方法
获得 synchronized 隐式锁的线程,调用带超时参数的 Object.wait(long timeout) 方法
调用带超时参数的 Thread.join(long millis) 方法
调用带超时参数的 LockSupport.parkNanos(Object blocker, long deadline) 方法
调用带超时参数的 LockSupport.parkUntil(long deadline) 方法
从 NEW 到 RUNNABLE 状态
只要调用线程对象的 start() 方法就可以了
从 RUNNABLE 到 TERMINATED 状态
调用 interrupt() 方法
调用stop() 方法
创建多少线程合适?
计算方法
线程数 =CPU 核数 *CPU利用率* [ 1 +(I/O 耗时 / CPU 耗时)]
CPU耗时:apm工具可以精确到方法耗时
IO耗时:io相关的方法一般是知道的
CPU使用率是目标值也是确定的
CPU数量是确定的
线程数 = CPU可用核心数/(1 - 阻塞系数)
CPU可用核心数是确定的
阻塞系数=I/O 耗时/(I/O 耗时+CPU 耗时)
QPS的计算
QPS数=线程数*(1000/(I/O耗时+CPU耗时))
单位毫秒
每秒查询率(QPS,Queries-per-second)是对一个特定的查询服务器在规定时间内所处理流量多少的衡量标准
局部变量为什么安全?
局部变量的作用域是方法内部,因此放到了调用栈的栈帧里。 在Java中,new出来的对象在堆里,但局部变量在栈里
线程拥有独立栈帧,所以方法内变量相互隔离
当调用方法时,会创建新的栈帧,并压入调用栈;当方法返回时,对应的栈帧就会被自动弹出,栈帧和方法是同生共死的