join(long)与sleep(long)的区别

1.join(long)方法的源码

首先看join()源码:java

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

从源码中能够看出,join()直接调用了join(long)方法,join(long)源码以下:异步

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

经过阅读源码能够看出,是经过不断轮询的方式去观察线程是否仍是活动线程ide

join(0)是不断的询问线程的状态,直到线程销毁join()方法才会结束。函数

当millis>0时,不在是wait(0),而是wait(delay),delay是还剩余的millis时间。有人会问第一次wait(delay)后不就已经通过这millis的时间,为何还会有while执行屡次wait(delay)呢?由于这里不只要考虑wait在delay时间后被唤醒,还要考虑到在delay时间内,被notify唤醒,唤醒后尚未执行到millis的时间,所以要屡次调用wait(delay)方法。测试

2.比较join(long) 与 sleep(long),join方法后语句提早执行问题

join方法底层调用的是wait方法,执行到wait方法能够释放锁,而sleep方法不释放锁this

具体细节经过案例来说解:spa

首先定义两个线程类:MyThreadA,MyThreadB,其中为了保证两个线程能够同步执行,在MyThreadA中添加一个MyThreadB的实例变量,具体代码以下:线程

package com.feng.example;


public class MyThreadB extends Thread {


	@Override
	synchronized public void run() {

		try {
			System.out.println("begin B thread, ThreadName="+Thread.currentThread().getName()+"==="+System.currentTimeMillis());
			Thread.sleep(5000);
			System.out.println("end B thread, ThreadName="+Thread.currentThread().getName()+"==="+System.currentTimeMillis());
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

}
package com.feng.example;


public class MyThreadA extends Thread {

	private Thread b;
	
	public MyThreadA(Thread b)
	{
		this.b = b;
	}
	
	@Override
	public void run() {
		try {
			synchronized(b)
			{//只是为了可以和线程b同步
				System.out.println("begin A thread, ThreadName="+Thread.currentThread().getName()+"==="+System.currentTimeMillis());
				Thread.sleep(5000);
				System.out.println("end A thread, ThreadName="+Thread.currentThread().getName()+"==="+System.currentTimeMillis());
			}
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

测试类以下:code

package com.feng.example;

public class ThreadTest {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
				
		try {
			Thread b = new MyThreadB();
			Thread a = new MyThreadA(b);
			
			a.start();
			b.start();
			b.join(2000);
			
			System.out.println("main end"+"==="+System.currentTimeMillis());
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
			
	}
}

这个案例的结果并非惟一的。首先看第一种输出状况orm

begin A thread, ThreadName=Thread-1===1450080738885
end A thread, ThreadName=Thread-1===1450080743886
begin B thread, ThreadName=Thread-0===1450080743886
end B thread, ThreadName=Thread-0===1450080748886
main end===1450080748886

分析:线程a,b, b.join(2000),三者所执行的操做都是以线程实例b做为锁对象的,也就是说三者须要同步执行。通常来讲main函数中的代码执行要比启动线程的代码执行要快。(这不是重点),运行结果解释以下:

(1)三者中b.join(2000)首先抢到b的锁,而后代码执行到wait(delay)释放锁对象(去看上面的join(long)源码)

(2)线程a,b争抢锁,线程a得到锁对象,执行synchronized(b){}语句块,执行过程当中Thread.sleep(5000)不释放锁,直到执行完成

(3)线程b与b.join(2000)方法争抢锁,线程b抢到锁对象,执行run方法,直到执行完

(4)b.join(2000)得到锁,发现线程b已经销毁,join方法执行完毕。

(5)打印main end语句。

上述解释中join争抢锁能够是在a执行完以后,不影响输出结果。

再看第二种运行状况:

begin A thread, ThreadName=Thread-1===1450082014528
end A thread, ThreadName=Thread-1===1450082019529
main end===1450082019529
begin B thread, ThreadName=Thread-0===1450082019529
end B thread, ThreadName=Thread-0===1450082024530

解释以下:

(1)三者中b.join(2000)首先抢到b的锁,而后代码执行到wait(delay)释放锁对象(去看上面的join(long)源码)

(2)线程a,b争抢锁,线程a得到锁对象,执行synchronized(b){}语句块,执行过程当中Thread.sleep(5000)不释放锁,直到执行完成

(3)线程b与b.join(2000)方法争抢锁,b.join抢到锁,发现已经超过2s,所以join方法执行完成,输出main end,释放锁

(4)线程b得到锁,执行run方法

还有一只输出可能,这种可能很差演示,直接给出结果:

begin A thread, ThreadName=Thread-1===1450082014528
end A thread, ThreadName=Thread-1===1450082019529
begin B thread, ThreadName=Thread-0===1450082019529
main end===1450082019529
end B thread, ThreadName=Thread-0===1450082024530

解释以下:

(1)三者中b.join(2000)首先抢到b的锁,而后代码执行到wait(delay)释放锁对象(去看上面的join(long)源码)

(2)线程a,b争抢锁,线程a得到锁对象,执行synchronized(b){}语句块,执行过程当中Thread.sleep(5000)不释放锁,直到执行完成

(3)线程b与b.join(2000)方法争抢锁,b.join抢到锁,发现已经超过2s,所以join方法执行完成,释放锁

(4)线程b得到锁,在主线程的输出语句运行以前执行了线程b的run方法,这里main线程与b线程属于异步执行。

从上例中能够看出join与sleep的不一样,调用sleep时只是单纯的阻塞,而且不会释放锁。上例同时解释了join方法后语句提早执行的状况。

重点理解join方法获取锁,执行到wait方法直接释放锁的问题。

3.存在的困惑

主线程调用b.join方法,在join方法中是是让线程b执行wait方法,明明是线程b等待,又如何达到让主线程等待的功能呢?

b.wait到底wait的是什么,线程b为何还能执行????

自我解释:

首先b.wait(),b只是表明一个锁,等待的是执行b.wait()的线程。

join和wait同样,哪一个线程执行的此操做,等待的就是哪一个线程,和调用者没有关系,调用者只是一个锁对象而已。

相关文章
相关标签/搜索