join()方法原型:
- public final void join() throws InterruptedException
- public final void join(long) throws InterruptedException
- public final void join(long, int) throws InterruptedException
方法说明:举例说明,假设有线程对象A和线程对象B。在线程A中的某个方法中,线程B执行join()操作。当程序运行至B.join()操作的时候,线程A将会挂起,而执行线程B的操作,此时将会产生两种情况:
1、join()方法无参数,则线程A将会等待线程B执行完毕后,再继续执行
2、join()方法带参数(join(m)或者join(m,n)),则代表一个等待时间;当线程B开始执行后,线程A将会等待join()方法中指定的时间之后,不管线程B是否执行完毕,线程A恢复执行。
join()操作的异常及等待时间的处理
方法源代码如下:
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; } } } public final synchronized void join(long millis, int nanos) throws InterruptedException { //当号毫秒数小于0的时候,抛出异常 if (millis < 0) { throw new IllegalArgumentException("timeout value is negative"); } //当纳秒数小于0或者大于999999时,超范围,抛出异常 if (nanos < 0 || nanos > 999999) { throw new IllegalArgumentException( "nanosecond timeout value out of range"); } //当纳秒数大于500000,或者毫秒数为0而纳秒数不为0的时候,按一毫秒计算 if (nanos >= 500000 || (nanos != 0 && millis == 0)) { millis++; } //调用join(loing)方法 join(millis); } public final void join() throws InterruptedException { join(0); }
示例1:
class Sleeper extends Thread { private int duration; private double d = 0; public Sleeper(String name, int sleepTime) { super(name); duration = sleepTime; start(); } public String toString() { return Thread.currentThread().toString(); } public void run() { try { System.out.println(getName() + " start run()"); sleep(duration); } catch (InterruptedException e) { System.out.println(getName() + " was interrupted. " + "isInterrupted(): " + isInterrupted()); return; } System.out.println(getName() + " has awakened"); //耗时操作 for (int i = 0; i < 900000; i++) { d += (Math.E + Math.PI) / d; } System.out.println(getName() + "执行操作完毕!"); } } class Joiner extends Thread { private Sleeper sleeper; public Joiner(String name, Sleeper sleeper) { super(name); this.sleeper = sleeper; start(); } public String toString() { return Thread.currentThread().toString(); } public void run(){ try { System.out.println(getName() + " start run()"); sleeper.join(); } catch (InterruptedException e) { System.out.println("Interrupted"); } System.out.println(getName() + " join completed"); } } public class Joining { public static void main(String[] args) { Sleeper sleepy = new Sleeper("Sleepy", 5000), grumpy = new Sleeper("Grumpy", 5000); Joiner dopey = new Joiner("Dopey", sleepy), doc = new Joiner("Doc", grumpy); System.out.println("sleepy's id is " + sleepy.getId()); System.out.println("dopey's id is " + dopey.getId()); } }
执行结果 写道
Sleepy start run()
Grumpy start run()
sleepy's id is 8
dopey's id is 10
Dopey start run()
Doc start run()
Sleepy has awakened
Grumpy has awakened
Grumpy执行操作完毕!
Doc join completed
Sleepy执行操作完毕!
Dopey join completed
Grumpy start run()
sleepy's id is 8
dopey's id is 10
Dopey start run()
Doc start run()
Sleepy has awakened
Grumpy has awakened
Grumpy执行操作完毕!
Doc join completed
Sleepy执行操作完毕!
Dopey join completed
分析:
- 根据输出结果分析,前期,所有线程均启动
- dopey中的run()中,sleepy调用join()方法,根据输出的id可以得知,dopey和sleepy并非处于同一线程
- join()方法中无参数,当它被执行的时候,dopey会等待,直到sleepy执行完毕,dopey才会继续执行
示例2:将示例1中join()方法改为join(500)
执行结果 写道
sleepy's id is 8
dopey's id is 10
Sleepy start run()
Grumpy start run()
Dopey start run()
Doc start run()
Dopey join completed
Doc join completed
Sleepy has awakened
Grumpy has awakened
Sleepy执行操作完毕!
Grumpy执行操作完毕!
dopey's id is 10
Sleepy start run()
Grumpy start run()
Dopey start run()
Doc start run()
Dopey join completed
Doc join completed
Sleepy has awakened
Grumpy has awakened
Sleepy执行操作完毕!
Grumpy执行操作完毕!
分析:当join()加入参数500后,dopey只会等待sleepy500毫秒,在这个时间只会dopey会继续执行,而不会管sleepy是否会执行完毕。
join()的异常,示例:
class DemoA extends Thread { private double d = 0.0; public DemoA() { start(); } public void run() { System.out.println("start DemoA!"); while (!this.isInterrupted()) { for (int i = 0; i < 900000; i++) { d = d + (Math.PI + Math.E) / d; } //System.out.println("d = " + d); } System.out.println("end DemoA!"); } } class DemoB extends Thread { private Thread demo; public DemoB(Thread demo) { this.demo = demo; start(); } public void run() { System.out.println("start DemoB!"); try { demo.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("end DemoB!"); } } public class Hello { public static void main(String[] args) throws InterruptedException { DemoA a = new DemoA(); DemoB b = new DemoB(a); Thread.sleep(2000); b.interrupt(); Thread.sleep(2000); System.out.println("DemoA intreeupted is " + a.isInterrupted()); System.out.println("DemoB intreeupted is " + b.isInterrupted()); } }
执行结果 写道
start DemoA!
start DemoB!
end DemoB!
DemoA intreeupted is false
DemoB intreeupted is false
java.lang.InterruptedException
at java.lang.Object.wait(Native Method)
at java.lang.Thread.join(Thread.java:1280)
at java.lang.Thread.join(Thread.java:1354)
at com.test4.DemoB.run(Hello.java:35)
start DemoB!
end DemoB!
DemoA intreeupted is false
DemoB intreeupted is false
java.lang.InterruptedException
at java.lang.Object.wait(Native Method)
at java.lang.Thread.join(Thread.java:1280)
at java.lang.Thread.join(Thread.java:1354)
at com.test4.DemoB.run(Hello.java:35)
分析:当DemoB执行中断操作的时候,join()方法会产生异常,并且再得到DemoB的中断状态为false;根据JavaAPI得知,调用join()方法,如果一个线程中断了当前线程,会抛出java.lang.InterruptedException异常,并且线程的中断状态被清除。
注:本文代码原型源自《Think in Java》(Fourth Edition)中"21.2.11加入一个线程"。
本文是目前个人理解的结果,仅供参考,如后续发现问题,本人会进行相应的更正,也欢迎各位对Java线程感兴趣的朋友或者前辈进行指正。