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());
	}
}
执行结果 写道
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

 分析:

  • 根据输出结果分析,前期,所有线程均启动
  • 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执行操作完毕!

 分析:当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)

 分析:当DemoB执行中断操作的时候,join()方法会产生异常,并且再得到DemoB的中断状态为false;根据JavaAPI得知,调用join()方法,如果一个线程中断了当前线程,会抛出java.lang.InterruptedException异常,并且线程的中断状态被清除。

 

注:本文代码原型源自《Think in Java》(Fourth Edition)中"21.2.11加入一个线程"。

本文是目前个人理解的结果,仅供参考,如后续发现问题,本人会进行相应的更正,也欢迎各位对Java线程感兴趣的朋友或者前辈进行指正。

你可能感兴趣的:(中断,join(),join(),join()方法)