import java.util.concurrent.TimeUnit; public class JoinWaitTest { private static int a = 0; private static int b = 100; public static void main(String... args) throws InterruptedException{ Thread t = new Thread(new WaitThread()); t.start(); t.join(); System.out.println("I'm waiting for WaitThread end."); System.out.println("The result is " + (a + b)); } static class WaitThread implements Runnable { @Override public void run() { try { for (int i = 1; i < 6; i++) { TimeUnit.SECONDS.sleep(1); a++; System.out.println(i); } } catch (InterruptedException e) { } } } }
1html
2java
3编程
4多线程
5app
I'm waiting for WaitThread end.ide
The result is 105oop
在不少状况下,主线程生成并启动了子线程,若是子线程里要进行大量的耗时的运算,主线程每每将于子线程以前结束,可是若是主线程处理完其余的事务后,须要用到子线程的处理结果,也就是主线程须要等待子线程执行完成以后再结束,这个时候就要用到join()方法了。源码分析
本例只是个示例,演示的就是上述的过程。this
import java.util.concurrent.TimeUnit; public class JoinTest { public static void main(String... args) throws InterruptedException { Thread jt = new Thread(new JoinThread()); Thread tt = new Thread(new TimingThread()); tt.start(); tt.join(); jt.start(); } static class JoinThread implements Runnable { @Override public void run() { System.out.println("I have waited for too long."); } } static class TimingThread implements Runnable { @Override public void run() { for (int i = 0; i < 6; i++) { try { TimeUnit.SECONDS.sleep(1); System.out.println("Sleep end!"); } catch (InterruptedException e) { } } } } }
Sleep end!spa
Sleep end!
Sleep end!
Sleep end!
Sleep end!
Sleep end!
I have waited for too long.
跟源码示例1大同小异,只不过此次是jt线程要等待tt线程结束。
在 Java中,全部对象都可以被做为"监视器monitor"——指一个拥有一个独占锁,一个入口队列和一个等待队列的实体entity。
全部对象的非同步方法都可以在任意时刻被任意线程调用,此时不须要考虑加锁的问题。
而对于对象的同步方法来讲,在任意时刻有且仅有一个拥有该对象独占锁的线程可以调用它们。例如,一个同步方法是独占的。若是在线程调用某一对象的同步方法时,对象的独占锁被其余线程拥有,那么当前线程将处于阻塞状态,并添加到对象的入口队列中。
只有在调用线程拥有某个对象的独占锁时,才可以调用该对象的wait(),notify()和notifyAll()方法。若是尝试在未获取对象锁时调用这三个方法,那么你将获得一个"java.lang.IllegalMonitorStateException:current thread not owner"。
当一个线程正在某一个对象的同步方法中运行时调用了这个对象的wait()方法,那么这个线程将释放该对象的独占锁并被放入这个对象的等待队列,(JZ:意味着其余线程也能够再次调用同一个对象的wait方法)
注意,wait()方法强制当前线程释放对象锁。这意味着线程在调用某对象的wait()方法以前,当前线程必须已经得到该对象的锁。所以,线程必须在某个对象的同步方法或同步代码块中才能调用该对象的wait()方法。wait方法是native方法,里面的实现细节不清楚,可是线程A调用某对象B的wait方法确定默认线程A已经拥有了某对象B的锁(可以进入同步方法或同步代码块就说明线程A竞争到了对象锁)。若是跟这种默认(竞争获得锁)冲突,那么JVM就会报出运行时错误IllegalMonitorStateException(RuntimeException)。
当某线程调用某对象的 notify()或notifyAll()方法时,任意一个(对于notify())或者全部(对于notifyAll())在该对象的等待队列中的线程,将被转移到该对象的入口队列。接着这些队列(译者注:可能只有一个)将竞争该对象的锁,最终得到锁的线程继续执行。
若是没有线程在该对象的等待队列中等待得到锁,那么notify()和notifyAll()将不起任何做用。在调用对象的notify()和notifyAll()方法以前,调用线程必须已经获得该对象的锁。所以,必须在某个对象的同步方法或同步代码块中才能调用该对象的notify()或notifyAll()方法。
对于处于某对象的等待队列中的线程,只有当其余线程调用此对象的notify()或notifyAll()方法时才有机会继续执行。
调用wait()方法的缘由一般是,调用线程但愿某个特殊的状态(或变量)被设置以后再继续执行。调用notify()或notifyAll()方法的缘由一般是,调用线程但愿告诉其余等待中的线程:"特殊状态已经被设置"。这个状态做为线程间通讯的通道,它必须是一个可变的共享状态(或变量)。
例如,生产者线程向缓冲区中写入数据,消费者线程从缓冲区中读取数据。消费者线程须要等待直到生产者线程完成一次写入操做。生产者线程须要等待消费者线程完成一次读取操做。假设wait(),notify(),notifyAll()方法不须要加锁就可以被调用。
此时消费者线程调用wait()正在进入状态变量的等待队列(译者注:可能还未进入)。在同一时刻,生产者线程调用notify()方法打算向消费者线程通知状态改变。那么此时消费者线程将错过这个通知并一直阻塞。所以,对象的wait(),notify(),notifyAll()方法必须在该对象的同步方法或同步代码块中被互斥地调用。
[JZ]:这也是多线程编程里的一个经典问题,线程A进行锁操做的过程是非原子的,线程B就进行了释放的请求,致使线程A申请锁后没法释放!
http://www.cnblogs.com/jiangz222/p/4719671.html
http://www.blogjava.net/freeman1984/archive/2011/10/14/361306.html
/** * Waits at most {@code millis} milliseconds for this thread to * die. A timeout of {@code 0} means to wait forever. * * <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. It is recommended that * applications not use {@code wait}, {@code notify}, or * {@code notifyAll} on {@code Thread} instances. * * @param millis * the time to wait in milliseconds * * @throws IllegalArgumentException * if the value of {@code millis} is negative * * @throws InterruptedException * if any 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) 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; } } }
join()方法实质上就是join(0),最终执行代码以下所示
实质上调用代码1就至关于调用代码2
变一下:
while (isAlive()) {
if (millis <= now) {
break;
}
wait(millis - now);
now = System.currentTimeMillis() - base;
}
base和now都是时间。base是刚执行代码时的时间,now是执行代码流逝的时间。判断mills时间是否流逝完毕,流逝完毕则break跳出代码。