Java线程学习笔记(六):join()方法
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());
}
}
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)
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 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线程感兴趣的朋友或者前辈进行指正。
上一篇: .NET常用Request获取信息总结
下一篇: Java 泛型总结(三):通配符的使用