join()方法的作用:使所属的线程对象A正常执行,而使当前线程B进行无限期的阻塞,执行线程A执行结束销毁以后,线程B才会继续执行。
通过代码理解一下:
package join;
public class MyTest {
public static void main(String[] args) throws InterruptedException {
MyThread mt = new MyThread();
mt.start();
mt.join();
System.out.println("main Thread end:" + System.currentTimeMillis());
}
}
package join;
public class MyThread extends Thread {
public void run() {
System.out.println("MyThread begin:" + System.currentTimeMillis());
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
可以看出,main线程并没有立刻执行输出,而是等2秒以后,也就是MyThread线程执行结束以后,才继续执行。
join(long)方法:将上面的mt.join()改成mt.join(1000),执行结果
可以看出,mian线程只等待了1秒,并没有等待MyThread线程结束。
join(long)带参数的用法:
public class MyTest2 {
public static void main(String[] args) throws InterruptedException {
MyThreadA a = new MyThreadA();
MyThreadB b = new MyThreadB(a);
b.start();
b.join(1000);
System.out.println("打印1:" + System.currentTimeMillis());
a.start();
System.out.println("打印2:" + System.currentTimeMillis());
}
}
public class MyThreadB extends Thread {
private MyThreadA a;
public MyThreadB() {
}
public MyThreadB(MyThreadA a) {
this.a = a;
}
public void run() {
synchronized (a) {
try {
System.out.println("MyThreadB 执行了:" + System.currentTimeMillis());
Thread.sleep(5000);
System.out.println("MyThreadB 执行结束了:" + System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class MyThreadA extends Thread {
public synchronized void run() {
try {
System.out.println("MyThreadA 执行了:" + System.currentTimeMillis());
Thread.sleep(5000);
System.out.println("MyThreadA 执行结束:" + System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
分析下执行过程:
1、main线程执行b.start()方法,b线程处于了就绪状态,此时cpu并没有把时间资源给b线程, 所以main线程接着执行了b.join(1000),main线程阻塞1秒钟。
2、b线程获得了时间资源执行了run()方法,并且获得了线程a的锁。
3、b线程执行sleep(5000),sleep()方法并不会释放锁,此时main线程等待了1秒以后,main线程处于了就绪状态,由于b线程还处于阻塞,因此main线程获得了时间资源,执行了‘打印1’。
4、main线程继续往下执行,调用a对象start(),由于start方法是同步的,因此main线程需要等b线程释放对象a的锁,所以main线程又进入阻塞状态。
5、5秒以后线程b释放对象a的锁,main线程获得了a的锁,执行了a.start()方法,此时a线程处于就绪状态,与第一条类似,main线程优先执行了‘打印2’。
6、最后线程a执行run()方法,5秒后结束
将MyThreadB类稍作修改。
public class MyThreadB extends Thread {
private MyThreadA a;
public MyThreadB() {
}
public MyThreadB(MyThreadA a) {
this.a = a;
}
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
synchronized (a) {
try {
System.out.println("MyThreadB 执行了:" + System.currentTimeMillis());
Thread.sleep(5000);
System.out.println("MyThreadB 执行结束了:" + System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
读者可以自行分析此执行结果的过程。
join(long)与sleep(long)的区别:两者最大的区别就在于,join(long)方法是使用wait(long)时间的,因此具有释放锁的效果,而sleep并不会释放锁。
最后附上start(),join()源码
public synchronized void start() {
/**
* This method is not invoked for the main method thread or "system"
* group threads created/set up by the VM. Any new functionality added
* to this method in the future may have to also be added to the VM.
*
* A zero status value corresponds to state "NEW".
*/
if (threadStatus != 0)
throw new IllegalThreadStateException();
group.add(this);
start0();
if (stopBeforeStart) {
stop0(throwableFromStop);
}
}
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;
}
}
}
可以看出2个方法都是同步的。
本文详细解析了Java中线程的join方法及其带参数的使用方式,对比了join(long)与sleep(long)的区别,并提供了具体的代码示例帮助理解。

6648

被折叠的 条评论
为什么被折叠?



