本文共 6655 字,大约阅读时间需要 22 分钟。
1.join()的作用
调用某个线程的join()方法时,这个方法会挂起调用线程,直到被调用线程结束执行,调用线程才会继续执行。
2.放上join()的源码
/** * Waits for this thread to die. * *An invocation of this method behaves in exactly the same * way as the invocation * *
* {@linkplain #join(long) join}{@code (0)} ** * @throws InterruptedException * if any thread has interrupted the current thread. The * interrupted status of the current thread is * cleared when this exception is thrown. */ public final void join() throws InterruptedException { join(0); }
/** * Waits at most {@code millis} milliseconds for this thread to * die. A timeout of {@code 0} means to wait forever. * *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 * interrupted status 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; } } }
/** * Waits at most {@code millis} milliseconds plus * {@code nanos} nanoseconds for this thread to die. * *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 * interrupted status 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); }
3.分析
1)join()共有三个重载版本,join()和join(long millis, int nanos)最后都调用了join(long millis)。
2)带参数的 join() 都是 synchronized方法。
3)join() 调用了 join(0),从源码可以看到 join(0) 不断检查当前线程(join() 所属的线程实例,非调用线程)是否是 Active。如果被调用线程的对象生成了,但是未启动,调用它的join()是没有作用的,将继续向下执行。
4)当一个线程调用另一个线程的join()时,会先获取到被调用线程的锁,然后调用wait方法释放掉被调用线程的锁。
5)join()具有使线程排队运行的作用,有些类似同步的运行效果,join()与synchronized的区别是:join()在内部使用wait()方法进行等待,而synchronized关键字使用的是“对象监视器”原理作为同步。
6)join() 和 sleep() 一样,都可以被中断(被中断时,会抛出 InterrupptedException 异常);不同的是,join() 内部调用了 wait(),会释放锁,而 sleep() 会一直持有锁,如下所示:
类ThreadB.java代码如下:
package com.smile13.joinandsleep;/** * Created by eric on 2018/7/31. */public class ThreadB extends Thread { @Override public void run() { try { System.out.println(" b run begin thimer = " + System.currentTimeMillis()); Thread.sleep(5000); System.out.println(" b run end thimer = " + System.currentTimeMillis()); } catch (InterruptedException e) { e.printStackTrace(); } } public synchronized void bService() { System.out.println("打印了 bService timer = " + System.currentTimeMillis()); }}
类ThreadA.java代码如下:
package com.smile13.joinandsleep;/** * Created by eric on 2018/7/31. */public class ThreadA extends Thread { private ThreadB b; public ThreadA(ThreadB b) { super(); this.b = b; } @Override public void run() { try { synchronized (b) { b.start(); Thread.sleep(6000); // 不释放锁 } } catch (InterruptedException e) { e.printStackTrace(); } }}
类ThreadC.java代码如下:
package com.smile13.joinandsleep;/** * Created by eric on 2018/7/31. */public class ThreadC extends Thread { private ThreadB threadB; public ThreadC(ThreadB threadB) { super(); this.threadB = threadB; } @Override public void run() { threadB.bService(); }}
类Run.java代码如下:
package com.smile13.joinandsleep;/** * Created by eric on 2018/7/31. */public class Run { public static void main(String[] args) { try { ThreadB b = new ThreadB(); ThreadA a = new ThreadA(b); a.start(); Thread.sleep(1000); ThreadC c = new ThreadC(b); c.start(); } catch (InterruptedException e) { e.printStackTrace(); } }}
程序Run.java运行后的效果如下所示:
b run begin thimer = 1533050891103 b run end thimer = 1533050896103打印了 bService timer = 1533050897103
说明:由于线程ThreadA使用Thread.sleep(long millis)方法一直持有ThreadB对象的锁,时间达到6秒,所以线程ThreadC只有在ThreadA时间达到6秒后释放ThreadB对象的锁时,才能调用ThreadB中的同步方法bService(),上面的实验证明Thread.sleep(long millis)不会释放锁。
下面修改ThreadA的代码,验证join()方法会释放锁。
修改ThreadA.java类的代码如下:
package com.smile13.joinandsleep;/** * Created by eric on 2018/7/31. */public class ThreadA extends Thread { private ThreadB b; public ThreadA(ThreadB b) { super(); this.b = b; } @Override public void run() { try { synchronized (b) { b.start(); b.join(); // 说明join()释放锁 System.out.println("线程b执行完成,线程a继续执行..."); } } catch (InterruptedException e) { e.printStackTrace(); } }}
程序Run.java运行后的效果如下所示:
b run begin thimer = 1533052328339打印了 bService timer = 1533052329340 b run end thimer = 1533052333340线程b执行完成,线程a继续执行...
说明:由于线程ThreadA释放了ThreadB的锁,所以线程ThreadC可以调用ThreadB的同步方法bService(),此实验说明join()方法具有释放锁的特点。
4.未完待续....
转载地址:http://bdgsi.baihongyu.com/