欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

浅谈Java线程Thread.join方法解析

程序员文章站 2024-02-11 10:07:16
join字面上是加入的意思,我们先看看join方法的解释和实现。 /** * waits for this thread to die. * 调用...

join字面上是加入的意思,我们先看看join方法的解释和实现。

/**
   * waits for this thread to die.
   * 调用方线程(调用join方法的线程)执行等待操作,直到被调用的线程(join方法所属的线程)结束,再被唤醒
   * <p> an invocation of this method behaves in exactly the same
   * way as the invocation
   *
   *
   * @throws interruptedexception
   *     if any thread has interrupted the current thread. the
   *     <i>interrupted status</i> of the current thread is
   *     cleared when this exception is thrown.
   */
  public final void join() throws interruptedexception {
    join(0);
  }

这里join是调用的

/**
   * waits at most {@code millis} milliseconds for this thread to
   * die. a timeout of {@code 0} means to wait forever.
   * 等待线程执行结束,或者指定的最大等待时间到了,调用方线程再次被唤醒,如果最大等待时间为0,则只能等线程执行结束,才能被唤醒。
   * <p> this implementation uses a loop of {@code this.wait} calls
   * conditioned on {@code this.isalive}. as a thread terminates the
   * {@code this.notifyall} method is invoked. it is recommended that
   * applications not use {@code wait}, {@code notify}, or
   * {@code notifyall} on {@code thread} instances.
   *
   * 
   */
  public final synchronized void join(long millis)
  throws interruptedexception {
    long base = system.currenttimemillis();
    long now = 0;

    if (millis < 0) {
      throw new illegalargumentexception("timeout value is negative");
    }

    if (millis == 0) {
      while (isalive()) {
        wait(0);
      }
    } else {
      while (isalive()) {
        long delay = millis - now;
        if (delay <= 0) {
          break;
        }
        wait(delay);
        now = system.currenttimemillis() - base;
      }
    }
  }

可以看到,join方法本身是通过wait方法来实现等待的,这里判断如果线程还在运行中的话,则继续等待,如果指定时间到了,或者线程运行完成了,则代码继续向下执行,调用线程就可以执行后面的逻辑了。

但是在这里没有看到哪里调用notify或者notifyall方法,如果没有调用的话,那调用方线程会一直等待下去,那是哪里调用了唤醒它的方法呢?通过查证得知,原来在线程结束时,java虚拟机会执行该线程的本地exit方法,

//线程退出函数:
void javathread::exit(bool destroy_vm, exittype exit_type) {
...
//这里会处理join相关的销毁逻辑
ensure_join(this);
...
}
//处理join相关的销毁逻辑
  static void ensure_join(javathread* thread) {
   handle threadobj(thread, thread->threadobj());

   objectlocker lock(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();
  }

这样线程什么时候被唤醒就明白了。下面写个例子看下效果。

public class jointest {
  
  public static void main(string[] args) {
    
    threadboy boy = new threadboy();
    boy.start();
    
  }
  
  static class threadboy extends thread{
    @override
    public void run() {
      
      system.out.println("男孩和女孩准备出去逛街");
      
      threadgirl girl = new threadgirl();
      girl.start();
      
      try {
        girl.join();
      } catch (interruptedexception e) {
        e.printstacktrace();
      }
      
      system.out.println("男孩和女孩开始去逛街了");
    }
  }
  
  static class threadgirl extends thread{
    @override
    public void run() {
      int time = 5000;
      
      system.out.println("女孩开始化妆,男孩在等待。。。");
      
      try {
        thread.sleep(time);
      } catch (interruptedexception e) {
        e.printstacktrace();
      }
      
      system.out.println("女孩化妆完成!,耗时" + time);
      
    }
  }
  
}

执行结果为:

男孩和女孩准备出去逛街
女孩开始化妆,男孩在等待。。。
女孩化妆完成!,耗时5000
男孩和女孩开始去逛街了

就是男孩和女孩准备去逛街,女孩要化妆先,等女孩化妆完成了,再一起去逛街。

那join(time)的用法是怎么样的呢?

public class jointest {
  
  public static void main(string[] args) {
    
    threadboy boy = new threadboy();
    boy.start();
    
  }
  
  static class threadboy extends thread{
    @override
    public void run() {
      
      system.out.println("男孩和女孩准备出去逛街");
      
      threadgirl girl = new threadgirl();
      girl.start();
      
      int time = 2000;
      try {
        girl.join(time);
      } catch (interruptedexception e) {
        e.printstacktrace();
      }
      
      system.out.println("男孩等了" + time + ", 不想再等了,去逛街了");
    }
  }
  
  static class threadgirl extends thread{
    @override
    public void run() {
      int time = 5000;
      
      system.out.println("女孩开始化妆,男孩在等待。。。");
      
      try {
        thread.sleep(time);
      } catch (interruptedexception e) {
        e.printstacktrace();
      }
      
      system.out.println("女孩化妆完成!,耗时" + time);
      
    }
  }
  
}

这里仅仅把join方法换成了join(time)方法,描述改了点,打印的结果是:

男孩和女孩准备出去逛街
女孩开始化妆,男孩在等待。。。
男孩等了2000, 不想再等了,去逛街了
女孩化妆完成!,耗时5000

男孩等了join(time)中的time时间,如果这个time时间到达之后,女孩所在的线程还没执行完,则不等待了,继续执行后面的逻辑,就是不等女孩了,自己去逛街。

由此看出,join方法是为了比较方便的实现两个线程的同步执行,线程1执行,碰到线程2后,等待线程2执行后,再继续执行线程1的执行,加入的意思现在就比较形象化了。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。