写在前面:
在并发编程时,我们很容易会遇到输出一个数字的时候,可能得不到我们理想中的结果,那这是为什么呢?先让我们看一个最简单的例子。
示例1:
package test2;
/**
*
* @ClassName Test1
* @Description:测试线程输出结果
* @author McGRADY
* @date 2018年3月5日
*/
public class Test1 implements Runnable {
public static int result = 0;
@Override
public void run() {
for (int i = 0; i < 10; i++) {
result = result + 1;
}
}
public static void main(String[] args) {
Runnable thread = new Test1();
Thread t = new Thread(thread);
t.start();
System.out.println(result);
}
}
我们想让控制台输出10,但是实际情况下,控制可能输出的是0,为什么?这是因为,线程调用了start方法之后,并没有开始,而是进入RUNNABLE状态,等待CPU的调度,而这时,主函数就已经开始执行输出语句,所以,我们每次得到的结果可能就是0。
问题:那么怎么样,才能让我们得到输出为10呢?
答案:就是使用Join方法
现在我们再来看一下修改过的代码:
package test2;
/**
*
* @ClassName Test1
* @Description:测试线程输出结果
* @author McGRADY
* @date 2018年3月5日
*/
public class Test1 implements Runnable {
public static int result = 0;
@Override
public void run() {
for (int i = 0; i < 10; i++) {
result = result + 1;
}
}
public static void main(String[] args) throws Exception {
Runnable thread = new Test1();
Thread t = new Thread(thread);
t.start();
t.join();//添加的代码
System.out.println(result);
}
}
我们只是在start方法之后,加入了一行代码,就能完成我们理想中的输出。
Join方法:
介绍:假设A、B线程正在进行,但当A线程执行到了B线程Join方法时,A线程就会停止运行,等待线程B执行完毕,才会执行A线程。
作用:用于使得主线程暂停下来,等待子线程执行。
我们来看下JDK8中,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;
}
}
}
在源码中,我们可以看出,实际上是通过while循环判断子线程是否结束,如果未结束,就调用wait方法等待。有参数的方法,会通过当前时间-初始时间,来判断已经执行了多久,如果执行的时间>mills,就会停止等待,继续执行主线程。