join方法的扇入探究

Posted clover-forever

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了join方法的扇入探究相关的知识,希望对你有一定的参考价值。

join的探究

首先明确join的作用:t.join()方法只会使主线程(或者说是t.join()的线程)进入等待池并等待t线程执行完毕后才被唤醒。但是并不会影响同一时刻其他处在运行状态的线程。

下面来分析一下有无join()的差别:

无join时:

// 资源类
package com.join;

public class ThreadTest extends Thread{
    private String name;

    public ThreadTest(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println(name+"--->"+i);
        }
    }
}

// 测试方法
package com.join;

public class Demo {
    public static void main(String[] args) throws InterruptedException {
        ThreadTest t1 = new ThreadTest("A");
        ThreadTest t2 = new ThreadTest("B");

        t1.start();
        System.out.println("t1111111111111111111111111111111");
        t2.start();
        System.out.println("t2222222222222222222222222222222");

    }
}


运行结果
t1111111111111111111111111111111
A--->0
A--->1
A--->2
A--->3
A--->4
t2222222222222222222222222222222
B--->0
B--->1
B--->2
B--->3
B--->4

可以看出:t1,t2线程以及main执行时随机无序的。

但是加入join()时候:

package com.join;

public class Demo {
    public static void main(String[] args) throws InterruptedException {
        ThreadTest t1 = new ThreadTest("A");
        ThreadTest t2 = new ThreadTest("B");

        t1.start();
        t1.join();
        System.out.println("t1111111111111111111111111111111");
        t2.start();

        System.out.println("t2222222222222222222222222222222");

    }
}

可以看出t2线程在线程t1之后执行:

package com.join;

public class Demo {
    public static void main(String[] args) throws InterruptedException {
        ThreadTest t1 = new ThreadTest("A");
        ThreadTest t2 = new ThreadTest("B");

        t1.start();
        
        System.out.println("t1111111111111111111111111111111");
        t2.start();
        t1.join();
        System.out.println("t2222222222222222222222222222222");

    }
}

t1111111111111111111111111111111
A--->0
A--->1
A--->2
A--->3
B--->0
B--->1
B--->2
B--->3
B--->4
A--->4
t2222222222222222222222222222222

这种情况可以看出来:t1与t2仍然交替打印,随机无序的。

为了深入理解,我们看一下join()的源码:

public final void join() throws InterruptedException {
        join(0);            //join()等同于join(0)
    }

public final synchronized void join(long millis)
    throws InterruptedException {
        long base = System.currentTimeMillis();
        long now = 0;
		// 如果小于0抛出异常
        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }

		// 如果还活着,就调用wait
        if (millis == 0) {
            while (isAlive()) {
                wait(0);
            }
        } else {
            // 如果还活着,还是会调用wait方法
            while (isAlive()) {
                long delay = millis - now;
                if (delay <= 0) {
                    break;
                }
                wait(delay);
                now = System.currentTimeMillis() - base;
            }
        }
    }

从源码可以看出,join()方法的底层是用wait()方法实现的,可以看出,join方法是一个同步方法,当主线程调用t1.join()的时候,主线程获得了t1对象的锁,随后进入方法,调用了t1对象的wait方法,使主线程进入了t1对象的等待池,此时,t1线程还在执行,并且后面的t2.start()还没有执行,因此,t2线程还没有开始。等到t1线程执行完毕之后,主线程继续执行,执行了t2.start(),t2线程才会执行。

因此,可以得出结论,t.join()方法只会使主线程进入等待池并等待t线程执行完毕后才会被唤醒,同时并不影响同一时刻其他正在执行的线程。

注意:join源码中,只会调用wait方法,并没有在结束时调用notify,这是因为线程在die的时候会自动调用自身的notifyAll方法,来释放所有的资源和锁。

参考文章链接:
https://blog.csdn.net/u013425438/article/details/80205693

以上是关于join方法的扇入探究的主要内容,如果未能解决你的问题,请参考以下文章

什么是扇入和扇出?

扇入Fan-in和扇出Fan-out

SQL 中 left join 的底层原理(各种JOIN的复杂度探究)

SQL 中 left join 的底层原理(各种JOIN的复杂度探究)

“扇入”和“扇出”是什么意思?

10个JavaScript代码片段,使你更加容易前端开发。