主线程等待子线程执行完成后再执行——Thread.join()

一、一个例子

private static void joinTest(List roles) {
Vector vector = new Vector<>(10);
for (int i=0;i<10;i++){
MyThread myThread = new MyThread("id"+i,"name"+i,roles);
Thread t = new Thread(myThread);
vector.add(t);
t.start();
}
for (Thread thread : vector){
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

public class MyThread implements Runnable{

private String id;
private String name;
private List roles;

public MyThread(String id,String name,List roles){
    this.name = name;
    this.id = id;
    this.roles = roles;
}

@Override
public void run() {
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    roles.add(name);
    System.out.println("执行了-id:"+id+"name:"+name+"roles size:"+roles.size());
}

public String getId() {
    return id;
}

public void setId(String id) {
    this.id = id;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public List getRoles() {
    return roles;
}

public void setRoles(List roles) {
    this.roles = roles;
}

}
输出结果:

开始:1515250426924
执行了-id:id2name:name2roles size:1
执行了-id:id1name:name1roles size:3
执行了-id:id0name:name0roles size:2
执行了-id:id4name:name4roles size:4
执行了-id:id6name:name6roles size:7
执行了-id:id7name:name7roles size:8
执行了-id:id8name:name8roles size:9
执行了-id:id5name:name5roles size:6
执行了-id:id3name:name3roles size:5
执行了-id:id9name:name9roles size:10
[name2, name0, name1, name4, name3, name5, name6, name7, name8, name9]
结束:1515250427932耗时:1008roles size:10
可以看出,上面每个线程执行1000ms,总时长1008ms.

二、源码分析

/**

  • Waits for this thread to die.
  • An invocation of this method behaves in exactly the same

  • way as the invocation
  • {@linkplain #join(long) join}{@code (0)}
  • @throws InterruptedException
  •      if any thread has interrupted the current thread. The
    
  •      interrupted status of the current thread is
    
  •      cleared when this exception is thrown.
    

*/
public final void join() throws InterruptedException {
join(0);
}
这里看清楚一点:join传参为0。

然后进入join方法:

/**

  • Waits at most {@code millis} milliseconds for this thread to
  • die. A timeout of {@code 0} means to wait forever.
  • 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.
  • @param millis
  •     the time to wait in milliseconds
    
  • @throws IllegalArgumentException
  •      if the value of {@code millis} is negative
    
  • @throws InterruptedException
  •      if any thread has interrupted the current thread. The
    
  •      interrupted status of the current thread is
    
  •      cleared when this exception is thrown.
    

*/
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;
    }
}

}
从源码可以看出,如果线程被生成了,但还未被起动,isAlive()将返回false,调用它的join()方法是没有作用的,将直接继续向下执行wait。而wait方法中有参数,也就是不用唤醒谁,只是不再执行wait,向下继续执行而已。

三、join总结

join方法的原理就是调用相应线程的wait方法进行等待操作的,例如A线程中调用了B线程的join方法,则相当于在A线程中调用了B线程的wait方法,当B线程执行完(或者到达等待时间),B线程会自动调用自身的notifyAll方法唤醒A线程,从而达到同步的目的。

你可能感兴趣的:(主线程等待子线程执行完成后再执行——Thread.join())