thread.Join把指定的线程加入到当前线程,可以将两个交替执行的线程合并为顺序执行的线程。比如在线程B中调用了线程A的Join()方法,直到线程A执行完毕后,才会继续执行线程B。或者说join() 的作用:让“主线程”等待“子线程”结束之后才能继续运行。
方法:
t.join(); //使调用线程 t 在此之前执行完毕。
t.join(1000); //等待 t 线程,等待时间是1000毫秒
public class TestThreadJoin {
public static void main(String[] args){
System.out.println("system start time:"+System.currentTimeMillis());
Thread A = new Thread(){
@Override
public void run() {
try {
sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
for(int i=0;i<10;i++){
System.out.println("current thread :"+
Thread.currentThread().getName());}
System.out.println("current thread :"+
Thread.currentThread().getName());
System.out.println("A thread execute end time :"+
System.currentTimeMillis()); }
};
Thread B = new Thread(A);
System.out.println("A name:"+A.getName());
System.out.println("B name:"+B.getName());
A.start();
B.start();
try {
System.out.println("current thread in
main:"+Thread.currentThread().getName());
B.join(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("main end time:"+System.currentTimeMillis());
}
}
system start time:1466060949347 A name:Thread-0 B name:Thread-1 current thread in main:main main end time:1466060949403 current thread :Thread-1 current thread :Thread-0 current thread :Thread-1 current thread :Thread-0 current thread :Thread-0 current thread :Thread-1 current thread :Thread-0 current thread :Thread-0 current thread :Thread-1 current thread :Thread-0 current thread :Thread-1 current thread :Thread-0 current thread :Thread-1 current thread :Thread-0 current thread :Thread-1 current thread :Thread-0 current thread :Thread-1 current thread :Thread-0 current thread :Thread-1 current thread :Thread-0 current thread :Thread-1 current thread :Thread-1 A thread execute end time :1466060949553 A thread execute end time :1466060949553
先上一段JDK中代码:
/**
* 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;
}
}
}
从代码上看,如果线程被生成了,但还未被起动,调用它的 join() 方法是没有作用的,将直接继续向下执行
Join方法实现是通过wait(小提示:Object 提供的方法)。 当main线程调用t.join时候,main线程会获得线程对象t的锁(wait 意味着拿到该对象的锁),调用该对象的wait(等待时间),直到该对象唤醒main线程 ,比如退出后。这就意味着main 线程调用t.join时,必须能够拿到线程t对象的锁
class
MyThread
extends
Thread {
public
void
run() {
System.out.println(getName() +
"开始sleep"
);
try
{
Thread.sleep(
2000
);
}
catch
(Exception e) {
e.printStackTrace();
}
System.out.println(getName() +
"结束sleep"
);
}
}
public
class
TestWaitNotify {
public
static
void
main(String[] args)
throws
Exception {
Thread myThread =
new
MyThread();
myThread.start();
synchronized
(myThread) {
myThread.wait();
}
System.out.println(
"wait结束."
);
}
}
|
myThread执行结束后,main线程中的wait操作就自动退出了。程序里也并没有看到有notify/notifyAll调用。
如果将程序改成下面这样:
class
MyThread
extends
Thread {
public
void
run() {
System.out.println(getName() +
"开始sleep"
);
try
{
Thread.sleep(
2000
);
}
catch
(Exception e) {
e.printStackTrace();
}
System.out.println(getName() +
"结束sleep"
);
}
}
public
class
TestWaitNotify {
public
static
void
main(String[] args)
throws
Exception {
Thread myThread =
new
MyThread();
myThread.start();
Object tmp =
new
Object();
synchronized
(tmp) {
tmp.wait();
}
System.out.println(
"wait结束."
);
}
}
|
wait操作作用在一个独立的对象上,而不是像前面那样作用于线程对象上。这时程序就会一直wait下去。
给人直观的感觉,要么是发生了虚假唤醒,要么是线程在结束的时候做了些事情。经过查找,终于在JDK1.7 API文档的带参数的join方法上发现了蛛丝马迹!它是这么说的:
This implementation uses a loop of this.wait calls conditioned on this.isAlive. As a thread terminates the this.notifyAll method is invoked. It is recommended that applications not use wait, notify, or notifyAll on Thread instances.
也就是说join的实现方式大概如下:
while
(
this
.isAlive()) {
this
.wait();
}
|
当线程结束的时候会调用notifyAll方法来让join方法返回,这个调用也影响了我们的应用程序。这也是为什么wait调用一定要放到一个循环中的因素之一。文档中也写明了不推荐我们的应用在Thread实例上调用wait, notify, or notifyAll。
在JDK1.7之前的API文档中是找不到这些描述的。碰到这样的问题只能去找JVM源码了。且在JDK1.7的文档中,这个信息还是出现在join方法上,调用wait/notify出问题的时候,如果事先不了解这个机制,又怎么会去看join方法的API呢!由此可见,一份好的JAVA DOC文档的重要性。