内容说明:整理 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 类中的构造方法:
Constructor | Description |
---|---|
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,继续追踪该问题