服务器之家

服务器之家 > 正文

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

时间:2021-03-19 11:55     来源/作者:Ihesong

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
   * 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是调用的

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
/**
   * 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方法,

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//线程退出函数:
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();
  }

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
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)的用法是怎么样的呢?

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
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的执行,加入的意思现在就比较形象化了。

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

原文链接:https://www.jianshu.com/p/367fa66bf3f2

标签:

相关文章

热门资讯

2020微信伤感网名听哭了 让对方看到心疼的伤感网名大全
2020微信伤感网名听哭了 让对方看到心疼的伤感网名大全 2019-12-26
yue是什么意思 网络流行语yue了是什么梗
yue是什么意思 网络流行语yue了是什么梗 2020-10-11
背刺什么意思 网络词语背刺是什么梗
背刺什么意思 网络词语背刺是什么梗 2020-05-22
Intellij idea2020永久破解,亲测可用!!!
Intellij idea2020永久破解,亲测可用!!! 2020-07-29
苹果12mini价格表官网报价 iPhone12mini全版本价格汇总
苹果12mini价格表官网报价 iPhone12mini全版本价格汇总 2020-11-13
返回顶部