异步回调之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");}@Overridepublic 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");}@Overridepublic 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.*/@Deprecatedpublic 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演示上.
坚持读书久了,会发现自己变得温文尔雅.技术坚持久了,理解也会越来越深.
多给自己一点坚持.云淡风轻 温文尔雅是由内而外的.