1.join()的作用
调用某个线程的join()方法时,这个方法会挂起调用线程,直到被调用线程结束执行,调用线程才会继续执行。
2.放上join()的源码
/**
* Waits for this thread to die.
*
* <p> An invocation of this method behaves in exactly the same
* way as the invocation
*
* <blockquote>
* {@linkplain #join(long) join}{@code (0)}
* </blockquote>
*
* @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);
}
/**
* Waits at most {@code millis} milliseconds for this thread to
* die. A timeout of {@code 0} means to wait forever.
*
* <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.
*
* @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
* <i>interrupted status</i> 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;
}
}
}
/**
* Waits at most {@code millis} milliseconds plus
* {@code nanos} nanoseconds for this thread to die.
*
* <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.
*
* @param millis
* the time to wait in milliseconds
*
* @param nanos
* {@code 0-999999} additional nanoseconds to wait
*
* @throws IllegalArgumentException
* if the value of {@code millis} is negative, or the value
* of {@code nanos} is not in the range {@code 0-999999}
*
* @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 synchronized void join(long millis, int nanos)
throws InterruptedException {
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (nanos < 0 || nanos > 999999) {
throw new IllegalArgumentException(
"nanosecond timeout value out of range");
}
if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
millis++;
}
join(millis);
}
3.分析
1)join()共有三个重载版本,join()和join(long millis, int nanos)最后都调用了join(long millis)。
2)带参数的 join() 都是 synchronized方法。
3)join() 调用了 join(0),从源码可以看到 join(0) 不断检查当前线程(join() 所属的线程实例,非调用线程)是否是 Active。如果被调用线程的对象生成了,但是未启动,调用它的join()是没有作用的,将继续向下执行。
4)当一个线程调用另一个线程的join()时,会先获取到被调用线程的锁,然后调用wait方法释放掉被调用线程的锁。
5)join()具有使线程排队运行的作用,有些类似同步的运行效果,join()与synchronized的区别是:join()在内部使用wait()方法进行等待,而synchronized关键字使用的是“对象监视器”原理作为同步。
6)join() 和 sleep() 一样,都可以被中断(被中断时,会抛出 InterrupptedException 异常);不同的是,join() 内部调用了 wait(),会释放锁,而 sleep() 会一直持有锁,如下所示:
类ThreadB.java代码如下:
package com.smile13.joinandsleep;
/**
* Created by eric on 2018/7/31.
*/
public class ThreadB extends Thread {
@Override
public void run() {
try {
System.out.println(" b run begin thimer = " + System.currentTimeMillis());
Thread.sleep(5000);
System.out.println(" b run end thimer = " + System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public synchronized void bService() {
System.out.println("打印了 bService timer = " + System.currentTimeMillis());
}
}
类ThreadA.java代码如下:
package com.smile13.joinandsleep;
/**
* Created by eric on 2018/7/31.
*/
public class ThreadA extends Thread {
private ThreadB b;
public ThreadA(ThreadB b) {
super();
this.b = b;
}
@Override
public void run() {
try {
synchronized (b) {
b.start();
Thread.sleep(6000); // 不释放锁
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
类ThreadC.java代码如下:
package com.smile13.joinandsleep;
/**
* Created by eric on 2018/7/31.
*/
public class ThreadC extends Thread {
private ThreadB threadB;
public ThreadC(ThreadB threadB) {
super();
this.threadB = threadB;
}
@Override
public void run() {
threadB.bService();
}
}
类Run.java代码如下:
package com.smile13.joinandsleep;
/**
* Created by eric on 2018/7/31.
*/
public class Run {
public static void main(String[] args) {
try {
ThreadB b = new ThreadB();
ThreadA a = new ThreadA(b);
a.start();
Thread.sleep(1000);
ThreadC c = new ThreadC(b);
c.start();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
程序Run.java运行后的效果如下所示:
b run begin thimer = 1533050891103
b run end thimer = 1533050896103
打印了 bService timer = 1533050897103
说明:由于线程ThreadA使用Thread.sleep(long millis)方法一直持有ThreadB对象的锁,时间达到6秒,所以线程ThreadC只有在ThreadA时间达到6秒后释放ThreadB对象的锁时,才能调用ThreadB中的同步方法bService(),上面的实验证明Thread.sleep(long millis)不会释放锁。
下面修改ThreadA的代码,验证join()方法会释放锁。
修改ThreadA.java类的代码如下:
package com.smile13.joinandsleep;
/**
* Created by eric on 2018/7/31.
*/
public class ThreadA extends Thread {
private ThreadB b;
public ThreadA(ThreadB b) {
super();
this.b = b;
}
@Override
public void run() {
try {
synchronized (b) {
b.start();
b.join(); // 说明join()释放锁
System.out.println("线程b执行完成,线程a继续执行...");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
程序Run.java运行后的效果如下所示:
b run begin thimer = 1533052328339
打印了 bService timer = 1533052329340
b run end thimer = 1533052333340
线程b执行完成,线程a继续执行...
说明:由于线程ThreadA释放了ThreadB的锁,所以线程ThreadC可以调用ThreadB的同步方法bService(),此实验说明join()方法具有释放锁的特点。
4.未完待续....