java线程的join方法源码分析的不解问题

1.首先通过源码可以看到join方法的底层逻辑还是使用当前线程对象的wait方法,也知道子线程执行完业务代码后,主线程才能解除阻塞。我认为既然使用的是wait方法,必然需要notify或notifyAll来唤醒,但唤醒的机制是什么?难道使用的线程的隐式钩子方式,当线程执行完后再进行notify?


2.伪代码,按自己的理解实现join方法,不知道这样对不对?

public class JoinTest {


public static void main(String[] args) throws InterruptedException {

    ThreadTest tt=new ThreadTest();

    tt.start();

    synchronized (tt) {

        tt.wait();

    }

    System.out.println("主线程继续。。。。");

}

}


class ThreadTest extends Thread {


public void run() {

    for(int i=0;i<5;i++){

        try {

            Thread.sleep(1000);

            System.out.println("i="+i);

        } catch (InterruptedException e) {

            e.printStackTrace();

        }

    }

}

}

//---输出结果输下----

i=0

i=1

i=2

i=3

i=4

主线程继续。。。。


梵蒂冈之花
浏览 586回答 3
3回答

繁星coding

上边已经回答你的问题,线程结束时会调用notifyAll。JVM底层实际是使用OS层提供的API来支持线程的,比如UNIX-Like的OS中一般使用pthread(Windows也有Pthread的实现),openjdk的hotspotVM使用的就是pthread,我们来看一下openjdk8版本的hotspotVM底层实际代码。在Thread执行start的方法时,就会调用native方法的start0,start0底层实际经过很多层的封装,最终会调用createJavaThread的方法,createJavaThread就会调pthread_create创建一个线程并执行。过程大致是这样的:Thread.start() -> start0() -> ... -> createJavaCreate() -> pthread_create() => threadStart() => attachThread() -> 执行Thread的run() -> detachThread() "这个方法最后会调用Object.notifyAll"。openjdk-8-8u66-b17/jamvm-2.0.0/src/thread.cvoid createJavaThread(Object *jThread, long long stack_size) {&nbsp; &nbsp; Thread *self = threadSelf();&nbsp; &nbsp; ExecEnv *ee = sysMalloc(sizeof(ExecEnv));&nbsp; &nbsp; Thread *thread = sysMalloc(sizeof(Thread));&nbsp; &nbsp; memset(ee, 0, sizeof(ExecEnv));&nbsp; &nbsp; memset(thread, 0, sizeof(Thread));&nbsp; &nbsp; thread->ee = ee;&nbsp; &nbsp; ee->thread = jThread;&nbsp; &nbsp; ee->stack_size = stack_size;&nbsp; &nbsp; if(!classlibCreateJavaThread(thread, jThread)) {&nbsp; &nbsp; &nbsp; &nbsp; sysFree(thread);&nbsp; &nbsp; &nbsp; &nbsp; sysFree(ee);&nbsp; &nbsp; return;&nbsp; &nbsp; }&nbsp; &nbsp; disableSuspend(self);&nbsp; &nbsp; if(pthread_create(&thread->tid, &attributes, threadStart, thread)) {&nbsp; &nbsp; &nbsp; &nbsp; classlibMarkThreadTerminated(jThread);&nbsp; &nbsp; &nbsp; &nbsp; sysFree(ee);&nbsp; &nbsp; enableSuspend(self);&nbsp; &nbsp; &nbsp; &nbsp; signalException(java_lang_OutOfMemoryError, "can't create thread");&nbsp; &nbsp; &nbsp; &nbsp; return;&nbsp; &nbsp; }&nbsp; &nbsp; pthread_mutex_lock(&lock);&nbsp; &nbsp; /* Wait for thread to start */&nbsp; &nbsp; while(classlibGetThreadState(thread) == CREATING)&nbsp; &nbsp; &nbsp; &nbsp; pthread_cond_wait(&cv, &lock);&nbsp; &nbsp; pthread_mutex_unlock(&lock);&nbsp; &nbsp; enableSuspend(self);}....void *threadStart(void *arg) {&nbsp; &nbsp; Thread *thread = (Thread *)arg;&nbsp; &nbsp; Object *jThread = thread->ee->thread;&nbsp; &nbsp; /* Parent thread created thread with suspension disabled.&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp;This is inherited so we need to enable */&nbsp; &nbsp; enableSuspend(thread);&nbsp; &nbsp; /* Complete initialisation of the thread structure, create the thread&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp;stack and add the thread to the thread list */&nbsp; &nbsp; initThread(thread, INST_DATA(jThread, int, daemon_offset), &thread);&nbsp; &nbsp; /* Add thread to thread ID map hash table. */&nbsp; &nbsp; addThreadToHash(thread);&nbsp; &nbsp; /* Set state to running and notify creating thread */&nbsp; &nbsp; signalThreadRunning(thread);&nbsp; &nbsp; /* Execute the thread's run method */&nbsp; &nbsp; executeMethod(jThread, CLASS_CB(jThread->class)->method_table[run_mtbl_idx]);&nbsp; &nbsp; /* Run has completed.&nbsp; Detach the thread from the VM and exit */&nbsp; &nbsp; detachThread(thread);&nbsp; &nbsp; TRACE("Thread %p id: %d exited\n", thread, thread->id);&nbsp; &nbsp; return NULL;}void *detachThread(Thread *thread) {&nbsp; &nbsp; Object *keep_alive;&nbsp; &nbsp; ExecEnv *ee = thread->ee;&nbsp; &nbsp; Object *java_thread = ee->thread;&nbsp; &nbsp; Object *group = INST_DATA(java_thread, Object*, group_offset);&nbsp; &nbsp; /* If there's an exception pending, it is uncaught */&nbsp; &nbsp; if(exceptionOccurred0(ee))&nbsp; &nbsp; &nbsp; &nbsp; uncaughtException();&nbsp; &nbsp; /* Don't do anything if this is the main thread */&nbsp; &nbsp; if(thread->prev == NULL)&nbsp; &nbsp; &nbsp; &nbsp; return NULL;&nbsp; &nbsp; /* remove thread from thread group */&nbsp; &nbsp; executeMethod(group, (CLASS_CB(group->class))->&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; method_table[rmveThrd_mtbl_idx], java_thread);&nbsp; &nbsp; /* Remove thread from the ID map hash table */&nbsp; &nbsp; deleteThreadFromHash(thread);&nbsp; &nbsp; objectLock(java_thread);&nbsp; &nbsp; /* Mark the thread as terminated.&nbsp; This state is used in determining&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;if the thread is alive and so must be done before notifying joining&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;threads.&nbsp; The VM thread structure is tied to a Java-level object&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp;(see comment below).&nbsp; The keep_alive is an object which must be&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;kept alive to prevent the structure from being freed while we are&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;still accessing it */&nbsp; &nbsp; keep_alive = classlibMarkThreadTerminated(java_thread);&nbsp; &nbsp; /* Notify any threads waiting on the thread object -&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; these are joining this thread 这里调用objectNotifyAll */&nbsp; &nbsp; objectNotifyAll(java_thread);&nbsp; &nbsp; objectUnlock(java_thread);&nbsp; &nbsp; /* Thread's about to die, so no need to enable suspend&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;afterwards. */&nbsp; &nbsp; disableSuspend(thread);&nbsp; &nbsp; /* Grab global lock, and update thread structures protected by&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;it (thread list, thread ID and number of daemon threads) */&nbsp; &nbsp; pthread_mutex_lock(&lock);&nbsp;/* It is safe to free the thread's ExecEnv and stack now as these are&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp;only used within the thread.&nbsp; It is _not_ safe to free the native&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;thread structure as another thread may be concurrently accessing it.&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp;However, they must have a reference to the java level thread --&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;therefore, it is safe to free during GC when the thread is determined&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;to be no longer reachable. */&nbsp; &nbsp; sysFree(ee->stack);&nbsp; &nbsp; sysFree(ee);&nbsp; &nbsp; /* If no more daemon threads notify the main thread (which&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;may be waiting to exit VM).&nbsp; Note, this is not protected&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp;by lock, but main thread checks again */&nbsp; &nbsp; if(non_daemon_thrds == 0) {&nbsp; &nbsp; &nbsp; &nbsp; /* No need to bother with disabling suspension&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;around lock, as we're no longer on thread list */&nbsp; &nbsp; &nbsp; &nbsp; pthread_mutex_lock(&exit_lock);&nbsp; &nbsp; &nbsp; &nbsp; pthread_cond_signal(&exit_cv);&nbsp; &nbsp; &nbsp; &nbsp; pthread_mutex_unlock(&exit_lock);&nbsp; &nbsp; }&nbsp; &nbsp; /* Finally, clear the thread local data */&nbsp; &nbsp; setThreadSelf(NULL);&nbsp; &nbsp; TRACE("Thread %p id: %d detached from VM\n", thread, thread->id);&nbsp; &nbsp; return keep_alive;}....

函数式编程

子线程执行完毕之后,会调用exit()方法。exit()方法是线程执行完毕之后,由系统自动调用,可以看API介绍。exit()方法会调用notifyAll()。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java