原来还能这么看Java线程的状态及转换( 四 )

源码:
https://hg.openjdk.java.net/jdk8u/jdk8u/hotspot/file/69087d08d473/src/share/vm/runtime/thread.cpp 由于JavaThread定义可知JavaThread::JavaThread(ThreadFunction entry_point, size_t stack_sz)中参数entry_point是外部传入 , 那我们想想JavaThread是什么时候实例化的? 没错 , 就是我们一开始的JVM_StartThread中native_thread = new JavaThread(&thread_entry, sz); 也就是说this->entry_point()(this, this)实际上是回调的thread_entry方法
thread_entry源码:
static void thread_entry(JavaThread* thread, TRAPS) {HandleMark hm(THREAD);Handle obj(THREAD, thread->threadObj());JavaValue result(T_VOID);JavaCalls::call_virtual(&result,obj,KlassHandle(THREAD, SystemDictionary::Thread_klass()),vmSymbols::run_method_name(),vmSymbols::void_method_signature(),THREAD);}源码:
https://hg.openjdk.java.net/jdk8u/jdk8u/hotspot/file/69087d08d473/src/share/vm/prims/jvm.cpp 通过JavaCalls::call_virtual方法 , 又从JVM层 回到了Java语言层  , 即MyThread thread = new MyThread(); thread.start();
一切又回到了起点 , 这就是Javathread.start()内部完整的一个流程 , HotSpot虚拟机实现的Java线程其实是对Linux内核级线程的直接映射 , 将Java涉及到的所有线程调度、内存分配都交由操作系统进行管理 。
 
线程终止状态线程终止状态(TERMINATED) , 表示该线程已经运行完毕 。
当一个线程执行完毕 , 或者主线程的main()方法完成时 , 我们就认为它终止了 。终止的线程无法在被使用 , 如果调用start()方法 , 会抛出
java.lang.IllegalThreadStateException异常 , 这一点我们可以从start源码中很容易地得到
public synchronized void start() {if (threadStatus != 0)throw new IllegalThreadStateException();...}线程阻塞状态线程阻塞状态(BLOCKED) , 需要等待锁释放或者说获取锁失败时 , 线程阻塞
public class BlockedThread implements Runnable {@Overridepublic void run() {synchronized (BlockedThread.class){while (true){}}}}从Thread源码的注释中 , 我们可以知道等待锁释放或者说获取锁失败 , 主要有下面3中情况:

  1. 进入 synchronized 方法时
  2. 进入 synchronized 块时
  3. 调用 wait 后, 重新进入 synchronized 方法/块时
其中第三种情况 , 大家可以先思考一下 , 我们留在下文线程等待状态再详细展开
线程等待状态线程等待状态(WAITING) , 表示该线程需要等待其他线程做出一些特定动作(通知或中断) 。
wait/notify/notifyAll我们紧接着上一小节 , 调用wait 后, 重新进入synchronized 方法/块时 , 我们来看看期间发生了什么?
当线程1调用对象A的wait方法后 , 会释放当前的锁 , 然后让出CPU时间片 , 线程会进入该对象的等待队列中 , 线程状态变为 等待状态WAITING 。当另一个线程2调用了对象A的notify()/notifyAll()方法
notify()方法只会唤醒沉睡的线程 , 不会立即释放之前占有的对象A的锁 , 必须执行完notify()方法所在的synchronized代码块后才释放 。所以在编程中 , 尽量在使用了notify/notifyAll()后立即退出临界区
线程1收到通知后退出等待队列 , 并进入线程运行状态RUNNABLE , 等待 CPU 时间片分配, 进而执行后续操作 , 接着线程1重新进入 synchronized 方法/块时 , 竞争不到锁 , 线程状态变为线程阻塞状态BLOCKED 。如果竞争到锁 , 就直接接着运行 。线程等待状态 切换到线程阻塞状态 , 无法直接切换 , 需要经过线程运行状态 。
我们再来看一个例子 , 巩固巩固:
public class WaitNotifyTest {public static void main(String[] args) {Object A = new Object();new Thread(new Runnable() {@Overridepublic void run() {System.out.println("线程1等待获取 对象A的锁...");synchronized (A) {try {System.out.println("线程1获取了 对象A的锁");Thread.sleep(3000);System.out.println("线程1开始运行wait()方法进行等待 , 进入到等待队列......");A.wait();System.out.println("线程1等待结束");} catch (InterruptedException e) {e.printStackTrace();}}}}).start();new Thread(new Runnable() {@Overridepublic void run() {System.out.println("线程2等待获取 对象A的锁...");synchronized (A) {System.out.println("线程2获取了 对象A的锁");try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("线程2将要运行notify()方法进行唤醒线程1");A.notify();}}}).start();}}


推荐阅读