线程的join()方法

**

1. join() 的示例和作用

关于线程的join()方法,我们可以看下jdk1.8的介绍

public final void join() throws InterruptedException {
    join(0);
}

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;
        }
    }
}

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);
}

我们可以看到 join() 一共有三个重载版本(都是 final method,无法被子类覆盖):

1 public final void join() throws InterruptedException;
2 
3 public final synchronized void join(long millis) throws InterruptedException;
4 
5 public final synchronized void join(long millis, int nanos) throws InterruptedException;

其中又有

a. join() 和 join(long millis, int nanos) 最后都调用了 join(long millis)。

b. 带参数的 join() 都是 synchronized method。

c. join() 调用了 join(0),从源码可以看到 join(0) 不断检查当前线程(join() 所属的线程实例,非调用线程)是否是 Active。

d. join() 和 sleep() 一样,都可以被中断(被中断时,会抛出 InterrupptedException 异常);不同的是,join() 内部调用了 wait(),会出让锁,而 sleep() 会一直保持锁。

下面我们举个例子来解释下

示例

// 父线程
public class Parent extends Thread {
    public void run() {
        Child child = new Child();
        child.start();
        child.join();
        // ...
    }
}
// 子线程
public class Child extends Thread {
    public void run() {
        // ...
    }
}

上面代码展示了两个类:Parent(父线程类),Child(子线程类)。

  1. 在 Parent.run() 中,通过 Child child = new Child(); 新建 child 子线程(此时 child
    处于 NEW 状态);

  2. 然后再调用 child.start()(child 转换为 RUNNABLE 状态);

  3. 再调用 child.join()。

  4. 在 Parent 调用 child.join() 后,child 子线程正常运行,Parent 父线程会等待 child
    子线程结束后再继续运行。
    下面解释下这过程:
    Parent 调用 child.join(),child.join() 再调用 child.join(0) (此时 Parent 会获得 child 实例作为锁,其他线程可以进入 child.join() ,但不可以进入 child.join(0), 因为无法获取锁)。child.join(0) 会不断地检查 child 线程是否是 Active。
    如果 child 线程是 Active,则循环调用 child.wait(0)(为了防止 Spurious wakeup, 需要将 wait(0) 放入 for 循环体中;此时 Parent 会释放 child 实例锁,其他线程可以竞争锁并进入 child.join(0)。我们可以得知,可以有多个线程等待某个线程执行完毕)。
    一旦 child 线程不为 Active (状态为 TERMINATED), child.join(0) 会直接返回到 child.join(), child.join() 会直接返回到 Parent 父线程,Parent 父线程就可以继续运行下去了。

总结一下:简单来说就是当有多个线程的时候线程操作的对象被加锁了,必须等到这个对象的锁释放了我们才能继续后续操作,好比有很多个人要用一个东西,这个东西必须等到现在在用的人用完才能继续传下去。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值