对于thread的理解,一直停留在基本层面,想着加强一下理解。Ok,问题总是有的,当然收获也是美滋滋的。
先从一下demo开始lz的探索之旅,一步步揭开那神秘的面纱。
public class JoinTest implements Runnable{
public static int a = 0;
public void run() {
for (int k = 0; k < 5; k++) {
a = a + 1;
}
}
public static void main(String[] args) throws Exception {
Runnable r = new JoinTest();
Thread t = new Thread(r);
t.start();
t.join(); //加入join()
System.out.println(a);
}
}
相信很多人都见过这个demo,API对于jion的方法有如下解释:
“等待该线程终止。”(Waits for this thread to die.)
通俗点讲:就是等着a=5,的时候,再打印“a”。(这个实例实在有待改进,应该写个“the main thread is ended。”就好了)
也就是在子线程调用了join()方法后面的代码,只有等到子线程结束了才能执行。
关键点来了,我只想知道t是怎么加入到main函数的线程里面的。由于有个大侠在其博客里面画了很生动的图,把我绕晕了,加上不同的评论,不同的见解,疯了。
自己动手丰衣足食,开工!
Thread join源码出来:
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;
}
}
}
水平有限,问题立刻出现wait(0),怎么理解,继续,come on !
void notify()
随机选择一个在该对象上调用wait方法的线程,解除其阻塞状态。该方法只能在同步方法或同步块内部调用。如果当前线程不是锁的持有者,该方法抛出一个IllegalMonitorStateException异常。
void wait()
导致线程进入等待状态,直到它被其他线程通过notify()或者notifyAll唤醒。该方法只能在同步方法中调用。如果当前线程不是锁的持有者,该方法抛出一个IllegalMonitorStateException异常。
基于这个理解,我以为wait的作用对象应该是t,等待的也是t,可是为什么实际执行的是t,等待的确实main thread,抓狂!
wait,synchronized,notify,同步锁。。。看看另一位大侠的解惑:
wait()使用:
当前线程必须拥有此 对象监视器 。该线程发布对此监视器的所有权并等待 ,直到其他线程通过调用 notify 方法,或 notifyAll 方法通知在此对象的监视器上等待的线程醒来。
然后该线程将等到重新获得对监视器的所有权后才能继续执行。
对于某一个参数的版本,实现中断和虚假唤醒是可能的,而且此方法应始终在循环中使用:
synchronized (obj) {
while (<condition does not hold>)
obj.wait();
// Perform action appropriate to condition
}
此方法只应由作为此对象监视器的所有者的线程来调用。抛出: IllegalMonitorStateException - 如果当前线程不是此对象监视器的所有者。
首先,我们都知道JVM会给每一个对象都分配唯一的一把锁。这把锁是在对象中的。
然后,当Thread-0线程获得了这把锁后,应该是在对象中的锁内记录下当前占有自己的线程号,并把自己设置为已被占用。
那么当Thread-0需要放弃锁的时候,锁对象会把 Thread-0放入到锁的等待队列中 。而这一切和Thread-0是没有任何关系的。
自然也轮不到Thread-0对象来调用某个方法来改变另一个对象中的锁(这一点也说不通,我自己的锁凭什么让你来改)。
因此,也就出现用改变公共数据区对象的锁的方法是通过共数据区对象本省来调用,和线程对象是没有关系的。
事实上,每一个同步锁lock下面都挂了几个线程队列,包括就绪(Ready)队列,等待(Waiting)队列等。
当线程A因为得不到同步锁lock,从而进入的是lock.ReadyQueue(就绪队列),一旦同步锁不被占用,JVM将自动运行就绪队列中的线程而不需要任何notify()的操作。
但是当线程A被wait()了,那么将进入lock.WaitingQuene(等待队列),同时如果占据的同步锁也会放弃。而此时如果同步锁不唤醒等待队列中的进程(lock.notify()),
这些进程将永远不会得到运行的机会。
谜底揭开:
当main线程调用t.join时候,main线程会获得线程对象t的锁(wait 意味着拿到该对象的锁),调用该对象的wait(等待时间),直到该对象唤醒main线程 ,比如退出后。
这就意味着main 线程调用t.join时,必须能够拿到线程t对象的锁。
感谢各位大侠的解惑,希望给大家理解带来帮助。
问渠那得清如许,为有源头活水来。大侠的推荐:
先从一下demo开始lz的探索之旅,一步步揭开那神秘的面纱。
public class JoinTest implements Runnable{
public static int a = 0;
public void run() {
for (int k = 0; k < 5; k++) {
a = a + 1;
}
}
public static void main(String[] args) throws Exception {
Runnable r = new JoinTest();
Thread t = new Thread(r);
t.start();
t.join(); //加入join()
System.out.println(a);
}
}
相信很多人都见过这个demo,API对于jion的方法有如下解释:
“等待该线程终止。”(Waits for this thread to die.)
通俗点讲:就是等着a=5,的时候,再打印“a”。(这个实例实在有待改进,应该写个“the main thread is ended。”就好了)
也就是在子线程调用了join()方法后面的代码,只有等到子线程结束了才能执行。
关键点来了,我只想知道t是怎么加入到main函数的线程里面的。由于有个大侠在其博客里面画了很生动的图,把我绕晕了,加上不同的评论,不同的见解,疯了。
自己动手丰衣足食,开工!
Thread join源码出来:
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;
}
}
}
水平有限,问题立刻出现wait(0),怎么理解,继续,come on !
void notify()
随机选择一个在该对象上调用wait方法的线程,解除其阻塞状态。该方法只能在同步方法或同步块内部调用。如果当前线程不是锁的持有者,该方法抛出一个IllegalMonitorStateException异常。
void wait()
导致线程进入等待状态,直到它被其他线程通过notify()或者notifyAll唤醒。该方法只能在同步方法中调用。如果当前线程不是锁的持有者,该方法抛出一个IllegalMonitorStateException异常。
基于这个理解,我以为wait的作用对象应该是t,等待的也是t,可是为什么实际执行的是t,等待的确实main thread,抓狂!
wait,synchronized,notify,同步锁。。。看看另一位大侠的解惑:
wait()使用:
当前线程必须拥有此 对象监视器 。该线程发布对此监视器的所有权并等待 ,直到其他线程通过调用 notify 方法,或 notifyAll 方法通知在此对象的监视器上等待的线程醒来。
然后该线程将等到重新获得对监视器的所有权后才能继续执行。
对于某一个参数的版本,实现中断和虚假唤醒是可能的,而且此方法应始终在循环中使用:
synchronized (obj) {
while (<condition does not hold>)
obj.wait();
// Perform action appropriate to condition
}
此方法只应由作为此对象监视器的所有者的线程来调用。抛出: IllegalMonitorStateException - 如果当前线程不是此对象监视器的所有者。
首先,我们都知道JVM会给每一个对象都分配唯一的一把锁。这把锁是在对象中的。
然后,当Thread-0线程获得了这把锁后,应该是在对象中的锁内记录下当前占有自己的线程号,并把自己设置为已被占用。
那么当Thread-0需要放弃锁的时候,锁对象会把 Thread-0放入到锁的等待队列中 。而这一切和Thread-0是没有任何关系的。
自然也轮不到Thread-0对象来调用某个方法来改变另一个对象中的锁(这一点也说不通,我自己的锁凭什么让你来改)。
因此,也就出现用改变公共数据区对象的锁的方法是通过共数据区对象本省来调用,和线程对象是没有关系的。
事实上,每一个同步锁lock下面都挂了几个线程队列,包括就绪(Ready)队列,等待(Waiting)队列等。
当线程A因为得不到同步锁lock,从而进入的是lock.ReadyQueue(就绪队列),一旦同步锁不被占用,JVM将自动运行就绪队列中的线程而不需要任何notify()的操作。
但是当线程A被wait()了,那么将进入lock.WaitingQuene(等待队列),同时如果占据的同步锁也会放弃。而此时如果同步锁不唤醒等待队列中的进程(lock.notify()),
这些进程将永远不会得到运行的机会。
谜底揭开:
当main线程调用t.join时候,main线程会获得线程对象t的锁(wait 意味着拿到该对象的锁),调用该对象的wait(等待时间),直到该对象唤醒main线程 ,比如退出后。
这就意味着main 线程调用t.join时,必须能够拿到线程t对象的锁。
感谢各位大侠的解惑,希望给大家理解带来帮助。
问渠那得清如许,为有源头活水来。大侠的推荐:
对于object的wait、notify、notifyAll的理解,可以参见《Java 虚拟机体系结构 》中堆内存区的内容,就会有更加深刻的理解了。
转载地址:http://blog.youkuaiyun.com/wjbtian/article/details/19547283