异步回调之Join

join:异步阻塞之闷葫芦

阻塞模式实现泡茶实例首先从基础的多线程join合并实验入手.join操作的原理是阻塞当前线程,直到待合并的目标线程执行完成.

线程的合并流程

Java中线程的合并流程是:假设线程A调用线程B的join()方法去合并B线程,那么线程A进入阻塞状态,直到线程B执行完成.

泡茶例子中,主线程通过分别调用烧水线程和清洗线程的join()方法,等待烧水线程和清洗线程完成,然后主线程执行泡茶操作.流程参考图如下.

通过join()实现异步泡茶喝

通过join实现一个异步阻塞版本,参考如下.

public class JoinDemo {

    public static final int SLEEP_GAP = 500;

    public static String getCurrentThreadName() {
        return Thread.currentThread().getName();
    }

    static class HotWaterThread extends Thread {
        public HotWaterThread() {
            super("烧水--Thread");
        }

        @Override
        public void run() {
            try {
                System.out.println("洗好水壶");
                System.out.println("灌上凉水");
                System.out.println("放在火上");
                Thread.sleep(SLEEP_GAP);
                System.out.println("水开了");
            } catch (InterruptedException e) {
                System.out.println("烧水失败");
            }
            System.out.println("运行结束");
        }
    }

    static class WashThread extends Thread {
        public WashThread() {
            super("清洗--Thread");
        }

        @Override
        public void run() {
            try {
                System.out.println("洗茶壶");
                System.out.println("洗茶杯");
                System.out.println("拿茶叶");
                Thread.sleep(SLEEP_GAP);
                System.out.println("洗完了");
            } catch (InterruptedException e) {
                System.out.println("洗茶壶茶杯失败");
            }
            System.out.println("运行结束");
        }
    }

    public static void main(String[] args) {
        WashThread washThread = new WashThread();
        HotWaterThread hotWaterThread = new HotWaterThread();
        washThread.start();
        hotWaterThread.start();

        try {
            washThread.join();
            hotWaterThread.join();
            Thread.currentThread().setName("主线程");
            System.out.println("泡茶喝");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(getCurrentThreadName() + "运行结束");
    }
}

程序中有三个线程:主线程main 烧水线程HotWaterThread 清洗线程WashThread,主线程调用了这两个线程的join方法进行合并.

Join()方法详解

join方法应用场景如下:

A线程调用B线程的join方法,等待B线程执行完成,在B线程没有完成之前,A线程阻塞.

Join()方法有三个重载版本:

    /**
     * Waits for this thread to die.
     *
     * <p> An invocation of this method behaves in exactly the same
     * way as the invocation
     *
     * <blockquote>
     * {@linkplain #join(long) join}{@code (0)}
     * </blockquote>
     *
     * @throws  InterruptedException
     *          if any thread has interrupted the current thread. The
     *          <i>interrupted status</i> of the current thread is
     *          cleared when this exception is thrown.
     */
    public final void join() throws InterruptedException {
        join(0);
    }

A线程等待B线程执行结束后,A线程重新开始执行. 

    /**
     * Counts the number of stack frames in this thread. The thread must
     * be suspended.
     *
     * @return     the number of stack frames in this thread.
     * @exception  IllegalThreadStateException  if this thread is not
     *             suspended.
     * @deprecated The definition of this call depends on {@link #suspend},
     *             which is deprecated.  Further, the results of this call
     *             were never well-defined.
     */
    @Deprecated
    public native int countStackFrames();

    /**
     * Waits at most {@code millis} milliseconds for this thread to
     * die. A timeout of {@code 0} means to wait forever.
     *
     * <p> This implementation uses a loop of {@code this.wait} calls
     * conditioned on {@code this.isAlive}. As a thread terminates the
     * {@code this.notifyAll} method is invoked. It is recommended that
     * applications not use {@code wait}, {@code notify}, or
     * {@code notifyAll} on {@code Thread} instances.
     *
     * @param  millis
     *         the time to wait in milliseconds
     *
     * @throws  IllegalArgumentException
     *          if the value of {@code millis} is negative
     *
     * @throws  InterruptedException
     *          if any thread has interrupted the current thread. The
     *          <i>interrupted status</i> of the current thread is
     *          cleared when this exception is thrown.
     */
    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;
            }
        }
    }

A线程等待B线程执行一段时间,最长时间为millis 毫秒,超过后就会A线程重新执行.

    /**
     * Waits at most {@code millis} milliseconds plus
     * {@code nanos} nanoseconds for this thread to die.
     *
     * <p> This implementation uses a loop of {@code this.wait} calls
     * conditioned on {@code this.isAlive}. As a thread terminates the
     * {@code this.notifyAll} method is invoked. It is recommended that
     * applications not use {@code wait}, {@code notify}, or
     * {@code notifyAll} on {@code Thread} instances.
     *
     * @param  millis
     *         the time to wait in milliseconds
     *
     * @param  nanos
     *         {@code 0-999999} additional nanoseconds to wait
     *
     * @throws  IllegalArgumentException
     *          if the value of {@code millis} is negative, or the value
     *          of {@code nanos} is not in the range {@code 0-999999}
     *
     * @throws  InterruptedException
     *          if any thread has interrupted the current thread. The
     *          <i>interrupted status</i> of the current thread is
     *          cleared when this exception is thrown.
     */
    public final synchronized void join(long millis, int nanos)
    throws InterruptedException {

        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }

        if (nanos < 0 || nanos > 999999) {
            throw new IllegalArgumentException(
                                "nanosecond timeout value out of range");
        }

        if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
            millis++;
        }

        join(millis);
    }

A线程等待B线程执行一段时间,最长时间为millis 毫秒加nanos纳秒,超过后就会A线程重新执行.

容易混淆的几点.

join()是实例方法,不是静态方法.

调用join方法时,不是thread所指向的目标线程阻塞,而是当前线程被阻塞.

只有等待的thread执行完成或者超时,当前线程才能启动执行.

总结下,join方法通过上面的源码可以看出,是不断通过检查线程是否存存活,来进行阻塞.直到被唤醒才会解除阻塞.而且join方法不能拿到返回结果,缺少很多的灵活性.所以join更多的停留在Demo演示上.

坚持读书久了,会发现自己变得温文尔雅.技术坚持久了,理解也会越来越深.

多给自己一点坚持.云淡风轻 温文尔雅是由内而外的.

如果大家喜欢我的分析的话,可以关注下我的微信公众号

心有九月星辰

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值