
今天我们来分享两道BT的多线程经典面试题,作者是黄俊老师。
黄俊老师,95后、23岁拿到阿里60w年薪,之后在美团拿到百万年薪,现在一心只想钻研技术。
由于文章篇幅较长,我们把两个问题分开来讲,避免有小伙伴搞不懂。
第一篇请点击:线程唤醒问题
接下来我们来看第二个问题:线程执行完isAlive方法返回true问题
样例代码:
public class ThreadAliveTest {public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> {System.out.println("t1 start");try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("t1 end");});t1.start();Thread t2 = new Thread(() -> {synchronized (t1) {System.out.println("t2 start");try {Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("t1 isAlive:" + t1.isAlive());}});t2.start();}}
输出结果:
t1 startt2 startt1 endt1 isAlive:true
问题:
分析:
public final native boolean isAlive();
首先看到isAlive方法由JNI方法实现。我们来看Hotspot源码。
JVM_ENTRY(jboolean, JVM_IsThreadAlive(JNIEnv* env, jobject jthread))JVMWrapper("JVM_IsThreadAlive");oop thread_oop = JNIHandles::resolve_non_null(jthread);return java_lang_Thread::is_alive(thread_oop);JVM_END
bool java_lang_Thread::is_alive(oop java_thread) { JavaThread* thr = java_lang_Thread::thread(java_thread); return (thr != NULL);}JavaThread* java_lang_Thread::thread(oop java_thread) { return (JavaThread*)java_thread->address_field(_eetop_offset);}
JVM_ENTRY(void, JVM_StartThread(JNIEnv* env, jobject jthread))JVMWrapper("JVM_StartThread");JavaThread *native_thread = NULL;bool throw_illegal_thread_state = false; // 非法线程状态标识{// Threads_lock上锁,保证C++的线程对象和操作系统原生线程不会被清除。当前方法执行完,也就是栈帧释放时,会释放这里的锁,当然肯定会调用析构函数,而这个对象的析构函数中调用unlock方法释放锁MutexLocker mu(Threads_lock);if (java_lang_Thread::thread(JNIHandles::resolve_non_null(jthread)) != NULL) { // 如果线程不为空,则表明线程已经启动,则为非法状态throw_illegal_thread_state = true;} else {// 本来这里可以检测一下stillborn标记来看看线程是否已经停止,但是由于历史原因,就让线程自己玩了,这里就不玩了// 取得线程对象的stackSize的大小jlong size = java_lang_Thread::stackSize(JNIHandles::resolve_non_null(jthread));// 开始创建C++ Thread对象和原生线程对象,使用无符号的线程栈大小,所以这里不会出现负数size_t sz = size > 0 ? (size_t) size :0;// 创建JavaThread,这里的thread_entry为传入的运行地址,也就是启动线程,需要一个入口执行点,这个函数地址便是入口执行点native_thread = new JavaThread(&thread_entry, sz);// 如果osthread不为空,则标记当前线程还没有被使用if (native_thread->osthread() != NULL) {native_thread->prepare(jthread);}}}// 如果throw_illegal_thread_state不为0,那么直接抛出异常if (throw_illegal_thread_state) {THROW(vmSymbols::java_lang_IllegalThreadStateException());}// 原生线程必然不能为空,因为线程是由操作系统创建的,所以没有OS线程,空有个JavaThread类有啥用0.0if (native_thread->osthread() == NULL) {delete native_thread; // 直接用C++的delete释放内存THROW_MSG(vmSymbols::java_lang_OutOfMemoryError(),"unable to create new native thread");}Thread::start(native_thread); // 一切准备妥当,开始启动线程JVM_END
void JavaThread::prepare(jobject jni_thread, ThreadPriority prio) {// 包装当前Java线程对象Handle thread_oop(Thread::current(),JNIHandles::resolve_non_null(jni_thread));// 将Java层面的线程Oop对象与JavaThread C++层面的对象关联set_threadObj(thread_oop());java_lang_Thread::set_thread(thread_oop(), this);// 设置优先级if (prio == NoPriority) {prio = java_lang_Thread::priority(thread_oop());}Thread::set_priority(this, prio);// 将JavaThread类放入到全局线程列表中Threads::add(this);}
void java_lang_Thread::set_thread(oop java_thread, JavaThread* thread) {// 将JavaThread C++层面的线程对象设置为Java层面的Thread oop对象的eetop变量java_thread->address_field_put(_eetop_offset, (address)thread);}
void JavaThread::exit(bool destroy_vm, ExitType exit_type) {...ensure_join(this);...}
static void ensure_join(JavaThread* thread) {// 封装Java Thread线程oop对象Handle threadObj(thread, thread->threadObj());// 获取Java Thread线程oop对象锁ObjectLocker lock(threadObj, thread);// 清除未处理的异常信息thread->clear_pending_exception();// 将状态修改为TERMINATEDjava_lang_Thread::set_thread_status(threadObj(), java_lang_Thread::TERMINATED);// 将Java Thread线程oop对象与JavaThread C++对象解绑java_lang_Thread::set_thread(threadObj(), NULL);// 唤醒所有阻塞在线程对象的线程lock.notify_all(thread);// 如果以上代码期间发生异常,那么清理挂起的异常thread->clear_pending_exception();}
ObjectLocker::ObjectLocker(Handle obj, Thread* thread, bool doLock) {_dolock = doLock;_thread = thread;if (_dolock) {// 获取Java Thread线程oop对象锁ObjectSynchronizer::fast_enter(_obj, &_lock, false, _thread);}}ObjectLocker::~ObjectLocker() {if (_dolock) {// 释放Java Thread线程oop对象锁ObjectSynchronizer::fast_exit(_obj(), &_lock, _thread);}}
总结:


👇推荐关注👇
有趣的行业资讯
干货技术分享
程序员的日常生活
......

文章转载自马士兵,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




