源码:
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中情况:
- 进入 synchronized 方法时
- 进入 synchronized 块时
- 调用 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();}}
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 冻虾变黑了还能吃吗
- 发型|以前的女演员是真敬业,扮丑扮到亲妈不认!哪像现在这么“敷衍”
- 陈意涵|黄晓明锤上加锤,怒揭陈意涵“双面玉女”骗局,原来杨颖真没说谎!
- 如何在夏季来临之时减掉大肚腩,最好还能拥有马甲线?
- 陈意涵|黄晓明锤上加锤,怒揭陈意涵“双面玉女”骗局,原来杨颖真没说谎
- 蜂蜜保质期一般为多长时间 蜂蜜放了五年还能吃吗
- 大米生虫还能吃吗 大米生虫子处理诀窍
- 江疏影|这一次,江疏影被扒了个底朝天!网友:没想到这么乱!
- 张静初|黄晓明锤上加锤,怒揭陈意涵“双面玉女”骗局,原来杨颖真没说谎
- ella|Ella陈嘉桦“还没这么女过”文案翻车,上次被骂道歉的还是白鹿
