线程的状态
操作系统层面:五种状态
初始状态:仅在语言层面创建了线程对象,还没有与操作系统相关联(new出来Thread对象,但没调用它的start方法)
可运行状态(就绪状态):线程被创建(与操作系统相关联),可以由CPU调度执行运行状态:获取了CPU时间片,正在运行的状态
当CPU时间片用完,将从运行状态转换至可运行状态,导致线程的上下文切换阻塞状态:
如果调用了阻塞API(如BIO读文件),这时线程实际上用不到CPU,会发生上下文切换,进入阻塞状态。
当BIO操作完,操作系统会唤醒它,线程变为可运行状态。
线程在阻塞状态中如果不被唤醒,调度器将永远不会调度它。
终止状态:线程已经执行完,生命周期已经结束,不会转为其他状态
JAVA API:六种状态
这是从Java API层面来描述的
根据Thread.State枚举,分为六种状态:
NEW:线程刚被创建,还没调用start()方法
RUNNABLE:调用start()方法之后,Java API层面的RUNNABLE状态包括操作系统层面的运行状态,可运行状态,阻塞状态
TERMINATED:线程执行完毕
TIMED_WAITING:有时限的等待,如调用sleep方法 WAITING:无时限的等待,如调用join方法
BLOCKED:正在阻塞,等待监视器锁的状态
TIMED_WAITING,WAITING,BLOCKED都是Java API层面对阻塞状态的细分
我们应该统筹规划,合理使用线程,达到最优效果
线程执行的过程
栈与栈帧:
JVM由堆,栈,方法区组成,每个线程启动后,虚拟机会为其分配一块栈内存
每个栈由多个栈帧(Frame)组成,方法调用时会产生栈帧,分配栈帧内存,方法执行完,栈帧内存释放。
一个线程同时只能执行一个方法,所以只有一个活动栈帧,对应当前执行的方法。
如下图:
线程状态转换
1:调用start方法
2:获得obj锁后调用wait方法,RUNNABLE-->WAITING
调用obj.notify,obj.notifyAll,t.interrupt方法,锁竞争成功WAITING-->RUNNABLE,锁竞争失败WAITING->BLOCKED
3:调用t.join()方法,当前线程RUNNABLE-->WAITING(当前线程在t线程锁对象的监视器上等待,join的底层原理是wait)
t线程运行结束或者调用当前线程interrupt方法,WAITING-->RUNNABLE
4:调用LockSupport.park()方法,RUNNABLE-->WAITING
调用LockSupport.park(目标线程)方法或者调用interrupt方法,WAITING-->RUNNABLE
5:获得obj锁后调用obj.wait(long n)方法,RUNNABLE-->TIMED_WAITING
等待超时或调用obj.notify,obj.notifyAll,t.interrupt方法,锁竞争成功TIMED_WAITING--
>RUNNABLE,锁竞争失败TIMED_WAITING->BLOCKED
6:调用t.join(long n)方法,RUNNABLE-->TIMED_WAITING(当前线程在t线程锁对象的监视器上等待)
t线程运行结束或等待超时或调用当前线程的interrupt方法,TIMED_WAITING-->RUNNABLE
7:调用Thread.sleep(long n)方法,RUNNABLE-->TIMED_WAITING
等待超时,TIMED_WAITING-->RUNNABLE
8:调用LockSupport.parkNanos(long nanos)或LockSupport.parkUntil(long millis)方法,RUNNABLE-->TIMED_WAITING
调用LockSupport.park(目标线程)方法或者调用interrupt方法或者等待超时,TIMED_WAITING--
>RUNNABLE
9:竞争锁失败,RUNNABLE-->BLOCKED
持有锁的线程执行完,唤醒BLOCKED的线程重新竞争,竞争成功的线程BLOCKED--
>RUNNABLE
10:当前线程所有代码运行完毕,RUNNABLE-->TERMINATED