public final void join() throws InterruptedException
等待该线程终止。
public final void join(long millis) throws InterruptedException
等待该线程终止的时间最长为 millis 毫秒。超时为 0 意味着要一直等下去。
public final void join(long millis, int nanos) throws InterruptedException
等待该线程终止的时间最长为 millis 毫秒 + nanos 纳秒。
这就意味着main 线程调用t.join 时,必须能够拿到线程t 对象的锁 ,如果拿不到它是无法wait 的,刚开的例子t.join(1000) 不是说明了main 线程等待1 秒,如果在它等待之前,其他线程获取了t 对象的锁,它等待时间可不就是1 毫秒了。
等待该线程终止。
public final void join(long millis) throws InterruptedException
等待该线程终止的时间最长为 millis 毫秒。超时为 0 意味着要一直等下去。
public final void join(long millis, int nanos) throws InterruptedException
等待该线程终止的时间最长为 millis 毫秒 + nanos 纳秒。
package basic.c_join;
public class TestJoinA {
public static void main(String[] args) {
Thread t = new Thread(new TestRunnableImpl());
t.start();
try {
t.join(1000); // 主线程只等1秒,不管子线程什么时候结束
System.out.println("joinFinish");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class TestRunnableImpl implements Runnable {
public void run() {
try {
System.out.println("Begin sleep");
// 如果改成sleep(2000), 那么主线程就会先结束
Thread.sleep(1000);
System.out.println("End sleep");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
其实Join 方法实现是通过wait (小提示:Object 提供的方法)。 当main 线程调用t.join 时候,main 线程会获得线程对象t 的锁 (wait 意味着拿到该对象的锁), 调用该对象的wait( 等待时间) ,直到该对象唤醒main 线程,比如退出后。
这就意味着main 线程调用t.join 时,必须能够拿到线程t 对象的锁 ,如果拿不到它是无法wait 的,刚开的例子t.join(1000) 不是说明了main 线程等待1 秒,如果在它等待之前,其他线程获取了t 对象的锁,它等待时间可不就是1 毫秒了。
package basic.c_join;
import org.apache.log4j.Logger;
public class TestJoinB {
private static Logger logger = Logger.getLogger(TestJoinB.class);
public static void main(String[] args) {
Thread t = new Thread(new RunnableImpl());
new ThreadTest(t).start(); // 这个线程会持有锁
t.start();
try {
// 因为线程对象t的锁已经被其他线程获得, 要
logger.debug("beforejoin");
t.join();
logger.debug("joinFinish");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class ThreadTest extends Thread {
private static Logger logger = Logger.getLogger(ThreadTest.class);
Thread thread;
public ThreadTest(Thread thread) {
this.thread = thread;
}
@Override
public void run() {
logger.debug("run1 before");
holdThreadLock();
logger.debug("run1 end");
}
public void holdThreadLock() {
synchronized (thread) {
logger.debug("getObjectLock");
try {
Thread.sleep(9000);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
logger.debug("ReleaseObjectLock");
}
}
}
class RunnableImpl implements Runnable {
private static Logger logger = Logger.getLogger(RunnableImpl.class);
public void run() {
logger.debug("run2 before");
try {
logger.debug("Begin sleep");
Thread.sleep(2000);
logger.debug("End sleep");
} catch (InterruptedException e) {
e.printStackTrace();
}
logger.debug("run2 end");
}
}