Java并发编程的艺术-thread.join()

内容说明:整理 Java并发编程的艺术中线程间通信,分析Thread.join() 使用案例时,不明白为什么 wait() 的是哪个线程

1. thread.join() 案例

案例说明:

① 使用 new Thread(new Runnable(previous), i) 创建线程名为 i 的线程

② 每个线程持有previous线程的引用,previous调用 thread.join() 方法

public class Join {
    public static void main(String[] args) throws InterruptedException {
        Thread previous = Thread.currentThread();
        for(int i = 0; i < 10; i++){
            Thread thread = new Thread(new Domino(previous), String.valueOf(i));
            thread.start();
            previous = thread;
        }
        TimeUnit.SECONDS.sleep(5);
        System.out.println(Thread.currentThread().getName() + " terminate.");
    }
    static class Domino implements Runnable{
        private Thread thread;
        public Domino(Thread thread){
            this.thread = thread;
        }

        @Override
        public void run() {
            try {
                thread.join();
            } catch (InterruptedException e) {

            }
            System.out.println(Thread.currentThread().getName() + " terminate.");
        }
    }
}

运行结果:

main terminate.
0 terminate.
1 terminate.
....

注释 run() 中的 thread.join() 后的运行结果:

1 terminate.
2 terminate.
0 terminate.
...
main terminate.

多次输入均是乱序的,main线程的打印命令最后才执行

2. ? wait for this thread to die

Thread类中join() 方法注释部分:waits for this thread to die

问题:waits 的主语是谁?this 是谁?

// Waits for this thread to die.
public final void join() throws InterruptedException {
    join(0);
}

先分析下 this :
深入理解 JVM pg 236:实例方法通过 " this " 访问访问方法所属的对象
在这里插入图片描述
那么上述字节码文件中的 this 是否是 Domino 类中的 thread 呢?

getfield:访问类字段和实例字段,即 getfield 指令是针对类对象或者实例对象

而 thread 是作为该实例对象的实例字段,由于 thread 是 Domino 中的属性,则此处的thread 应该是 Domino 的实例对象,即此处的匿名对象

Thread thread = new Thread(new Domino(previous), String.valueOf(i));

注意:此处讨论的 this 还不是调用 join() 方法的 this,只是为了说明 thread = new Thread(Runnable target) 中的 thread 与 target 的关系

3. thread && target

Thread 类中的构造方法:

ConstructorDescription
Thread()分配一个新的 Thread对象
Thread(Runnable target)分配一个新的 Thread对象
Thread(Runnable target, String name)分配一个新的 Thread对象并命名

Thread 类中共有8个构造方法,详情请查看 jdk1.8api

注释:target = null 则执行该线程的 run 方法,否则执行 target 的 run 方法

public Thread(Runnable target, String name) {
    init(null, target, name, 0);
}

由于 Runnable 接口中只有 run() 方法,使用 new Thread(Runnable target).start() 实际是使用了代理模式,由 thread 对象启动 target 中的 run 方法

总结:当执行 i = 0 第一层循环时,实际上涉及三个实例对象 thread,previous,new Domino(…)

4. thread.start() && synchronized

把 start 方法 poll 出来,因注意到该方法是 synchronized 修饰的

public synchronized void start() {
    try {
        start0();
        started = true;
    } finally {
      ...
    }
}

看到 synchronized 的时候,想到调用 wait() 会释放锁,thread 执行了synchronized 方法,说明获得锁的是 thread,不过由于main 是静态方法,而且开启JVM后就启动,持有的锁应该是类对象,好像也没有什么关系 =_= !!!

那这里的锁对象是啥呢?还没有想明白

5. isAlive( ) && wait()

回到 thread.join(),该方法又调用了 join(0)

输入参数 millis = 0 时 :不限时等待

public final synchronized void join(long millis)
    throws InterruptedException {
    ...
        if (millis == 0) {
        // isAlive() 判断线程是否存活
            while (isAlive()) {
            // 使当前线程等待直到其他线程调用 notify() 或 notifyAll()
                wait(0);
            }
        } 
        ...
    }

虽然执行的是 new Domain() 对象的run 方法,但开启的却是 thread 线程,因此,实际上涉及的两个线程分别为 new thread 线程和 previous 线程

问题:isAlive() 是谁在判断谁 isalive ?

//Tests if this thread is alive. A thread is alive if it has been started and has not yet died.
public final native boolean isAlive();

注意到注释部分用了 this,而不是 current,那是否说明:是当前线程在循环判断自己是否存活呢?

不是很确定,不过 join(0) 方法的注释部分给出了说明:

* <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. 

调用 isAlive() 和 wait() 的都是当前对象 this,也即 previous 线程,当该线程终止时,会调用 this.notifyAll() 唤醒等待的线程

那么 wait 的是哪个线程呢?

//Causes the current thread to wait until either another thread invokes the {@link java.lang.Object#notify()} method...
public final native void wait(long timeout) throws InterruptedException;

注意:注释部分使用 current thread 而非 this thread

那么 current thread 是哪个线程?

6. current thread && object

上面已经分析到 执行 run 方法的线程是 Thread 线程

Thread thread = new Thread(new Domino(previous), String.valueOf(i));
thread.start();

这个图画出来是这样的:感觉有点问题,需要继续学习,欢迎指正
在这里插入图片描述
即:当前线程是 i = 0 时创建的 thread【仅考虑 i = 0 时】,执行 wait() 的是 previous 线程,执行 wait() 会使当前线程 thread 等待

本例的执行流程:main(join()) <— thread0(wait()) <— thread1(wait()) …
仅当 main() 线程休眠结束后,后续线程才被 notify() 然后结束 wait()

总结:这个问题实际上还是没有理解清楚,比如 current thread wait() 的是哪个 Object?
猜测是 new Domino() 对象,但是该对象run 方法并没有被 synchronized 修饰;

还有 thread.start() 执行的是 target 中的方法,这个流程是怎样?

今天终于把 openjdk8 的源码编译出来了,先把编译过程总结一下,接下来学习 debug jdk,继续追踪该问题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值