好了,上一篇我们已经初步了解了线程的创建与运行,那么下面我们来说说关键字 join
稍微熟悉java线程的伙伴都知道,Synchronized可以加锁,防止多线程对资源的抢占,提高数据的安全性等等。当然提起Synchronized,大家可能还会想起join ,wait,notify等等。
我们先说下提下join吧,这个单词大家都熟悉,意思是 成为…的一员; 参加; 加入;。
我们来看一个程序。
package com.example.thread;
public class MyThreadPool {
public static void main(String[] args) throws Exception {
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("线程一开始"+Thread.currentThread());
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程一结束"+Thread.currentThread());
}
});
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("线程二开始"+Thread.currentThread());
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程二结束"+Thread.currentThread());
}
});
System.out.println("main 方法开始。。。。"+Thread.currentThread());
thread1.start();
thread2.start();
// thread1.join();
// thread2.join();
System.out.println("main 方法结束。。。。"+Thread.currentThread());
}
}
下面我们看下运行结果:
main 方法开始。。。。Thread[main,5,main]
main 方法结束。。。。Thread[main,5,main]
线程一开始Thread[Thread-0,5,main]
线程二开始Thread[Thread-1,5,main]
线程一结束Thread[Thread-0,5,main]
线程二结束Thread[Thread-1,5,main]
Process finished with exit code 0
这个没什么问题,主线程加两个线程启动,然后多线程运行,互不影响,线程一和线程二启动需要时间,所以主线程先结束了。然后线程一和线程二启动,等待5秒明显会最后结束。
那如果加上了join呢?我们看下运行结果:
main 方法开始。。。。Thread[main,5,main]
线程二开始Thread[Thread-1,5,main]
线程一开始Thread[Thread-0,5,main]
线程二结束Thread[Thread-1,5,main]
线程一结束Thread[Thread-0,5,main]
main 方法结束。。。。Thread[main,5,main]
我們來看下,主线程先启动是没有任何问题的,然后线程一和线程二启动了,它们相隔太短,又互不影响,所以开始的时候不一定哪个先输出,但是一定在main方法前先结束的。为什么呢?join!因为线程一和线程二调用了join方法!
我们来看下这个程序的运行,首先,三个线程启动,互不影响(join方法未调用之前),然后线程一和线程二都调用了join,首先线程一调用了join,线程一就夹在main线程开始于结束之间,然后线程二又调用join,也插队到了中间,所以线程二和线程一的方法先运行完。
那为什么呢?
大家来看下join()的源码:
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;
}
}
}
从代码中,我们可以发现。当millis==0时,会进入while( isAlive() )循环;即只要子线程是活的,主线程就不停的等待。
所以线程一和线程二实际上是抢占了main方法的资源,插队到了前面,自然会先运行完。
好了,今天就先到这里,明天再补上Synchronize吧【笑哭】