浅谈Java线程Thread.join方法解析
join字面上是加入的意思,我们先看看join方法的解释和实现。
/** *Waitsforthisthreadtodie. *调用方线程(调用join方法的线程)执行等待操作,直到被调用的线程(join方法所属的线程)结束,再被唤醒 *Aninvocationofthismethodbehavesinexactlythesame *wayastheinvocation * * *@throwsInterruptedException *ifanythreadhasinterruptedthecurrentthread.The *interruptedstatusofthecurrentthreadis *clearedwhenthisexceptionisthrown. */ publicfinalvoidjoin()throwsInterruptedException{ join(0); }
这里join是调用的
/**
*Waitsatmost{@codemillis}millisecondsforthisthreadto
*die.Atimeoutof{@code0}meanstowaitforever.
*等待线程执行结束,或者指定的最大等待时间到了,调用方线程再次被唤醒,如果最大等待时间为0,则只能等线程执行结束,才能被唤醒。
*Thisimplementationusesaloopof{@codethis.wait}calls
*conditionedon{@codethis.isAlive}.Asathreadterminatesthe
*{@codethis.notifyAll}methodisinvoked.Itisrecommendedthat
*applicationsnotuse{@codewait},{@codenotify},or
*{@codenotifyAll}on{@codeThread}instances.
*
*
*/
publicfinalsynchronizedvoidjoin(longmillis)
throwsInterruptedException{
longbase=System.currentTimeMillis();
longnow=0;
if(millis<0){
thrownewIllegalArgumentException("timeoutvalueisnegative");
}
if(millis==0){
while(isAlive()){
wait(0);
}
}else{
while(isAlive()){
longdelay=millis-now;
if(delay<=0){
break;
}
wait(delay);
now=System.currentTimeMillis()-base;
}
}
}
可以看到,join方法本身是通过wait方法来实现等待的,这里判断如果线程还在运行中的话,则继续等待,如果指定时间到了,或者线程运行完成了,则代码继续向下执行,调用线程就可以执行后面的逻辑了。
但是在这里没有看到哪里调用notify或者notifyAll方法,如果没有调用的话,那调用方线程会一直等待下去,那是哪里调用了唤醒它的方法呢?通过查证得知,原来在线程结束时,java虚拟机会执行该线程的本地exit方法,
//线程退出函数:
voidJavaThread::exit(booldestroy_vm,ExitTypeexit_type){
...
//这里会处理join相关的销毁逻辑
ensure_join(this);
...
}
//处理join相关的销毁逻辑
staticvoidensure_join(JavaThread*thread){
HandlethreadObj(thread,thread->threadObj());
ObjectLockerlock(threadObj,thread);
thread->clear_pending_exception();
java_lang_Thread::set_thread_status(threadObj(),java_lang_Thread::TERMINATED);
java_lang_Thread::set_thread(threadObj(),NULL);
//这里就调用notifyAll方法,唤醒等待的线程
lock.notify_all(thread);
thread->clear_pending_exception();
}
这样线程什么时候被唤醒就明白了。下面写个例子看下效果。
publicclassJoinTest{
publicstaticvoidmain(String[]args){
ThreadBoyboy=newThreadBoy();
boy.start();
}
staticclassThreadBoyextendsThread{
@Override
publicvoidrun(){
System.out.println("男孩和女孩准备出去逛街");
ThreadGirlgirl=newThreadGirl();
girl.start();
try{
girl.join();
}catch(InterruptedExceptione){
e.printStackTrace();
}
System.out.println("男孩和女孩开始去逛街了");
}
}
staticclassThreadGirlextendsThread{
@Override
publicvoidrun(){
inttime=5000;
System.out.println("女孩开始化妆,男孩在等待。。。");
try{
Thread.sleep(time);
}catch(InterruptedExceptione){
e.printStackTrace();
}
System.out.println("女孩化妆完成!,耗时"+time);
}
}
}
执行结果为:
男孩和女孩准备出去逛街
女孩开始化妆,男孩在等待。。。
女孩化妆完成!,耗时5000
男孩和女孩开始去逛街了
就是男孩和女孩准备去逛街,女孩要化妆先,等女孩化妆完成了,再一起去逛街。
那join(time)的用法是怎么样的呢?
publicclassJoinTest{
publicstaticvoidmain(String[]args){
ThreadBoyboy=newThreadBoy();
boy.start();
}
staticclassThreadBoyextendsThread{
@Override
publicvoidrun(){
System.out.println("男孩和女孩准备出去逛街");
ThreadGirlgirl=newThreadGirl();
girl.start();
inttime=2000;
try{
girl.join(time);
}catch(InterruptedExceptione){
e.printStackTrace();
}
System.out.println("男孩等了"+time+",不想再等了,去逛街了");
}
}
staticclassThreadGirlextendsThread{
@Override
publicvoidrun(){
inttime=5000;
System.out.println("女孩开始化妆,男孩在等待。。。");
try{
Thread.sleep(time);
}catch(InterruptedExceptione){
e.printStackTrace();
}
System.out.println("女孩化妆完成!,耗时"+time);
}
}
}
这里仅仅把join方法换成了join(time)方法,描述改了点,打印的结果是:
男孩和女孩准备出去逛街
女孩开始化妆,男孩在等待。。。
男孩等了2000,不想再等了,去逛街了
女孩化妆完成!,耗时5000
男孩等了join(time)中的time时间,如果这个time时间到达之后,女孩所在的线程还没执行完,则不等待了,继续执行后面的逻辑,就是不等女孩了,自己去逛街。
由此看出,join方法是为了比较方便的实现两个线程的同步执行,线程1执行,碰到线程2后,等待线程2执行后,再继续执行线程1的执行,加入的意思现在就比较形象化了。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。