说明:参考《Java多线程核心技术》
6、join
在很多情况下,主线程创建并启动子线程,如果子线程要进行大量的耗时运算,主线程往往将早于子线程结束之前结束,这时,如果主线程想等待子线程执行完成之后再结束,比如子线程处理一个数据,主线程要取得这个数据中的值,就要用到join()方法了。
public class JoinThread extends Thread {
@Override
public void run() {
try {
int testValue = (int) (random() * 10000);
System.out.println(testValue);
Thread.sleep(testValue);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class JoinThreadTest {
public static void main(String[] args) {
try {
JoinThread thread = new JoinThread();
thread.start();
thread.join();
System.out.println("who print first ??");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
5225
who print first ??
*/
方法join的作用是使所属的线程对象x正常执行run()方法中的任务,而使当前线程z进行无限期的阻塞,等待线程x销毁后再继续进行线程z后面的代码。
注意: 如果在join的过程中,当前线程对象呗中断则当前线程出现异常。
join(long)与sleep(long)
方法join(long)的功能在内部是使用wait(long)方法来实现的,所以join(long)方法具有释放锁的特性。源码如下:
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;
}
}
}
从源码中可以看到,当执行wait(long)方法后,当前线程的锁被释放,所以join()方法会释放锁。
但是sleep(long)方法却不释放锁。
public class JoinThreadA extends Thread{
private JoinThreadB joinThreadB;
public JoinThreadA(JoinThreadB joinThreadB) {
super();
this.joinThreadB = joinThreadB;
}
@Override
public void run() {
try {
synchronized (joinThreadB) {
joinThreadB.start();
Thread.sleep(6000);
//Thread.sleep(); // 不释放锁
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class JoinThreadB extends Thread{
@Override
public void run() {
try {
System.out.println("joinThreadB start time = " + System.currentTimeMillis());
Thread.sleep(5000);
System.out.println("joinThreadB end time = " + System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
synchronized public void threadBService() {
System.out.println("print threadBService time = " + System.currentTimeMillis());
}
}
public class JoinThreadC extends Thread {
private JoinThreadB joinThreadB;
public JoinThreadC(JoinThreadB joinThreadB) {
super();
this.joinThreadB = joinThreadB;
}
@Override
public void run() {
joinThreadB.threadBService();
}
}
public class JoinAndSleepTest {
public static void main(String[] args) {
try {
JoinThreadB joinThreadB = new JoinThreadB();
JoinThreadA joinThreadA = new JoinThreadA(joinThreadB);
joinThreadA.start();
Thread.sleep(1000);
JoinThreadC joinThreadC = new JoinThreadC(joinThreadB);
joinThreadC.start();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
joinThreadB start time = 1546879230246
joinThreadB end time = 1546879235253
print threadBService time = 1546879236253
*/
结果说明,只有在线程B结束后,释放持有线程B的锁,线程C才能调用其中的同步方法。
public class JoinThreadA extends Thread{
private JoinThreadB joinThreadB;
int num = 1000;
public JoinThreadA(JoinThreadB joinThreadB) {
super();
this.joinThreadB = joinThreadB;
}
@Override
public void run() {
try {
synchronized (joinThreadB) {
joinThreadB.start();
joinThreadB.join(); // 释放锁
for (int i = 0; i < num; i++) {
random();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class JoinThreadB extends Thread{
@Override
public void run() {
try {
System.out.println("joinThreadB start time = " + System.currentTimeMillis());
Thread.sleep(5000);
System.out.println("joinThreadB end time = " + System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
synchronized public void threadBService() {
System.out.println("print threadBService time = " + System.currentTimeMillis());
}
}
public class JoinThreadC extends Thread {
private JoinThreadB joinThreadB;
public JoinThreadC(JoinThreadB joinThreadB) {
super();
this.joinThreadB = joinThreadB;
}
@Override
public void run() {
joinThreadB.threadBService();
}
}
public class JoinAndSleepTest {
public static void main(String[] args) {
try {
JoinThreadB joinThreadB = new JoinThreadB();
JoinThreadA joinThreadA = new JoinThreadA(joinThreadB);
joinThreadA.start();
Thread.sleep(1000);
JoinThreadC joinThreadC = new JoinThreadC(joinThreadB);
joinThreadC.start();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
joinThreadB start time = 1546879230246
joinThreadB end time = 1546879235253
print threadBService time = 1546879236253
*/
从打印结果看到,在join过程中释放了当前持有的锁,才使得线程C调用线程B的同步方法。