一、 在研究 join 的用法之前,先明确 两件 事情 。
1.j oin 方法定 义 在 Thread 类 中, 则调 用者必 须 是一个 线 程,
例如:
Thread t = new Custom Thread(); // 这里一般是自定义的线程类
t .start();// 线程起动
t.join();// 此处 会 抛出 InterruptedException 异常
2. 上面的两行代码也是在一个线程里面执行的。
以上出现了两个线程,一个是我们自定义的线程类,我们实现了 run 方法,做一些我们需要的工作;另外一个线程,生成我们自定义线程类的对象,然后执行
custom Thread .start();
custom Thread .join();
在这种情况下,两个线程的关系是一个线程由另外一个线程生成并起动,所以我们暂且认为第一个线程叫做“子线程 ”,另外一个线程叫做“主线程 ”。
二、为什么要用 join() 方法
主线程生成并起动了子线程,而子线程里要进行大量的耗时的运算 ( 这里可以借鉴下线程的作用 ) ,当主线程处理完其他的事务后,需要用到子线程的处理结果,这个时候就要用到 join(); 方法了。
三、 join 方法的作用
在网上看到有人说“将两个线程合并”。这样解释我觉得理解起来还更麻烦。不如就借鉴下 API 里的说法:
“等待该线程终止。”
解释一下,是主线程 ( 我在“一”里已经命名过了 ) 等待子线程的终止。也就是在子线程调用了 join() 方法后面的代码,只有等到子线程结束了才能执行。(Waits for this thread to die.)
四、用实例来理解
写一个简单的例子来看一下 join() 的用法,一共三个类:
1.CustomThread 类
2. CustomThread1 类
3. JoinTestDemo 类, main 方法所在的类。
代码 1 :
- package wxhx.csdn2;
- /**
- *
- * @author bzwm
- *
- */
- class CustomThread1 extends Thread {
- public CustomThread1() {
- super ( "[CustomThread1] Thread" );
- };
- public void run() {
- String threadName = Thread.currentThread().getName();
- System.out.println(threadName + " start." );
- try {
- for ( int i = 0 ; i < 5 ; i++) {
- System.out.println(threadName + " loop at " + i);
- Thread.sleep(1000 );
- }
- System.out.println(threadName + " end." );
- } catch (Exception e) {
- System.out.println("Exception from " + threadName + ".run" );
- }
- }
- }
- class CustomThread extends Thread {
- CustomThread1 t1;
- public CustomThread(CustomThread1 t1) {
- super ( "[CustomThread] Thread" );
- this .t1 = t1;
- }
- public void run() {
- String threadName = Thread.currentThread().getName();
- System.out.println(threadName + " start." );
- try {
- t1.join();
- System.out.println(threadName + " end." );
- } catch (Exception e) {
- System.out.println("Exception from " + threadName + ".run" );
- }
- }
- }
- public class JoinTestDemo {
- public static void main(String[] args) {
- String threadName = Thread.currentThread().getName();
- System.out.println(threadName + " start." );
- CustomThread1 t1 = new CustomThread1();
- CustomThread t = new CustomThread(t1);
- try {
- t1.start();
- Thread.sleep(2000 );
- t.start();
- t.join();//在代碼2里,將此處注釋掉
- } catch (Exception e) {
- System.out.println("Exception from main" );
- }
- System.out.println(threadName + " end!" );
- }
- }
打印结果:
main start. //main 方法所在的线程起动,但没有马上结束,因为调用 t.join(); ,所以要等到 t 结束了,此线程才能向下执行。
[CustomThread1] Thread start. // 线程 CustomThread1 起动
[CustomThread1] Thread loop at 0 // 线程 CustomThread1 执行
[CustomThread1] Thread loop at 1 // 线程 CustomThread1 执行
[CustomThread] Thread start. // 线程 CustomThread 起动,但没有马上结束,因为调用 t1.join(); ,所以要等到 t1 结束了,此线程才能向下执行。
[CustomThread1] Thread loop at 2 // 线程 CustomThread1 继续执行
[CustomThread1] Thread loop at 3 // 线程 CustomThread1 继续执行
[CustomThread1] Thread loop at 4 // 线程 CustomThread1 继续执行
[CustomThread1] Thread end. // 线程 CustomThread1 结束了
[CustomThread] Thread end. // 线程 CustomThread 在 t1.join(); 阻塞处起动,向下继续执行的结果
main end! // 线程 CustomThread 结束,此线程在 t.join(); 阻塞处起动,向下继续执行的结果。
修改一下代码,得到代码 2 :(这里只写出修改的部分)
-
- public class JoinTestDemo {
- public static void main(String[] args) {
- String threadName = Thread.currentThread().getName();
- System.out.println(threadName + " start." );
- CustomThread1 t1 = new CustomThread1();
- CustomThread t = new CustomThread(t1);
- try {
- t1.start();
- Thread.sleep(2000 );
- t.start();
- // t.join();//在代碼2里,將此處注釋掉
- } catch (Exception e) {
- System.out.println("Exception from main" );
- }
- System.out.println(threadName + " end!" );
- }
- }
打印结果:
main start. // main 方法所在的线程起动,但没有马上结束,这里并不是因为 join 方法,而是因为 Thread.sleep(2000);
[CustomThread1] Thread start. // 线程 CustomThread1 起动
[CustomThread1] Thread loop at 0 // 线程 CustomThread1 执行
[CustomThread1] Thread loop at 1 // 线程 CustomThread1 执行
main end! // Thread.sleep(2000); 结束,虽然在线程 CustomThread 执行了 t1.join(); ,但这并不会影响到其他线程 ( 这里 main 方法所在的线程 ) 。
[CustomThread] Thread start. // 线程 CustomThread 起动,但没有马上结束,因为调用 t1.join(); ,所以要等到 t1 结束了,此线程才能向下执行。
[CustomThread1] Thread loop at 2 // 线程 CustomThread1 继续执行
[CustomThread1] Thread loop at 3 // 线程 CustomThread1 继续执行
[CustomThread1] Thread loop at 4 // 线程 CustomThread1 继续执行
[CustomThread1] Thread end. // 线程 CustomThread1 结束了
[CustomThread] Thread end. // 线程 CustomThread 在 t1.join(); 阻塞处起动,向下继续执行的结果
五、从源码看 join() 方法
在 CustomThread 的 run 方法里,执行了 t1.join(); ,进入看一下它的 JDK 源码:
- public final void join() throws InterruptedException {
- n(0 );
- }
然后进入 join(0) 方法:
- /**
- * Waits at most <code>millis</code> milliseconds for this thread to
- * die. A timeout of <code>0</code> means to wait forever. //注意这句
- *
- * @param millis the time to wait in milliseconds.
- * @exception InterruptedException if another 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) //参数millis为0.
- throws InterruptedException {
- long base = System.currentTimeMillis();
- long now = 0 ;
- if (millis < 0 ) {
- throw new IllegalArgumentException( "timeout value is negative" );
- }
- if (millis == 0 ) { //进入这个分支
- while (isAlive()) { //判断本线程是否为活动的。这里的本线程就是t1.
- wait(0 ); //阻塞
- }
- } else {
- while (isAlive()) {
- long delay = millis - now;
- if (delay <= 0 ) {
- break ;
- }
- wait(delay);
- now = System.currentTimeMillis() - base;
- }
- }
- }
单纯从代码上看,如果线程被生成了,但还未被起动,调用它的 join() 方法是没有作用的。将直接继续向下执行,这里就不写代码验证了。
本文来自优快云博客,转载请标明出处:http://blog.youkuaiyun.com/bzwm/archive/2009/02/12/3881392.aspx