1 前言
在Java线程编程中, join()方法主要是让调用该方法的thread在完成run方法里面的部分后, 再执行join()方法后面的代码。
比如:
public class Demo08 { public static void main(String[] args) throws InterruptedException { Thread08 thread08 = new Thread08(); thread08.start(); // thread08.join(); System.out.println("子线程执行完成以后再执行"); } } class Thread08 extends Thread{ @Override public void run() { try { int value = (int) (Math.random() * 10000); System.out.println("需要等待" + value + "毫秒"); Thread.sleep(value); } catch (InterruptedException e) { e.printStackTrace(); } } } 复制代码
不使用join方法的结果如下:
使用了join方法之后的运行结果如下:
输出第一句后等待9497毫秒,输出第二句。
join方法的作用就是使所属的线程对象A(子线程)执行run方法中的任务,而使得当前线程B(主线程)进行无限期的阻塞,等待线程A销毁后再继续 执行线程B后面的代码。方法join具有线程排队运行的作用,有些类似于同步代码运行的效果。
2 join的源码分析
从前面的例子可以发现,join具有使得线程排队的效果,就像同步一样。
但是join方法底层使用的是wait方法。
join的源码如下:
可以发现这里调用了join(long millis)方法,进入join(long millis)方法如下:
通过上面的方法可以发现当join(long millis)方法的参数是0时,运行这个方法的线程就会执行wait(0)。而wait方法的源码如下:
可以发现其实wait()方法其实执行的就是wait(0)。所以主线程一直等待。
而通过join(long milis)的源码可以发现,这个方法使用synchronized关键字进行修饰的,也就是调用这个方法需要获得子线程对象的锁,然后调用wait,即先获得锁后释放锁,然后等待唤醒。
当线程运行结束的时候,notify是被线程的子系统调用的,进而主线程被唤醒!
join与synchroinzed区别:join的内部使用wait方法进行等待,而synchronized关键字使用的是对象锁的机制作为同步。
3 join方法的使用
join(long)方法使用:方法join(long)中的参数是设定等待的时间。比如:
public class Demo10 { public static void main(String[] args) throws InterruptedException { Thread t = new Thread10(); t.start(); t.join(2000); System.out.println("主线程结束于" + System.currentTimeMillis()); } } class Thread10 extends Thread{ @Override public void run() { try { System.out.println("子线程开始于" + System.currentTimeMillis()); Thread.sleep(5000); System.out.println("子线程结束于" + System.currentTimeMillis()); }catch (InterruptedException e){ e.printStackTrace(); } } } 复制代码
结果如下:
上面代码如果改成使用sleep(2000),运行的效果还是等待2000毫秒,和使用join(2000)运行效果没一样,但是它们在同步的处理上不一样,前面源码分析提到join底层是使用wait来实现所以会释放锁,而sleep不释放锁!所以joing(long)方法也具有释放同步锁的特点
比如:
public class Demo11 { public static void main(String[] args) { Thread11_A thread11_a = new Thread11_A(); Thread11_B thread11_b = new Thread11_B(thread11_a); thread11_b.start(); Thread11_C thread11_c = new Thread11_C(thread11_a); thread11_c.start(); } } class Thread11_A extends Thread{ @Override public void run() { try{ System.out.println("线程A开始于:"+System.currentTimeMillis()); Thread.sleep(5000); System.out.println("线程A结束于:"+System.currentTimeMillis()); }catch(InterruptedException e){ e.printStackTrace(); } } synchronized public void foo(){ System.out.println("方法执行时间" + System.currentTimeMillis()); } } class Thread11_B extends Thread { private Thread11_A thread11_a; public Thread11_B(Thread11_A thread11_a) { this.thread11_a = thread11_a; } @Override public void run() { synchronized (thread11_a) { try { thread11_a.start(); // Thread.sleep(6000); thread11_a.join(); for (int i = 0; i < Integer.MAX_VALUE; i++) { String s = new String(); Math.random(); } }catch (InterruptedException e){ e.printStackTrace(); } } } } class Thread11_C extends Thread { private Thread11_A thread11_a; public Thread11_C(Thread11_A thread11_a) { this.thread11_a = thread11_a; } @Override public void run() { thread11_a.foo(); } } 复制代码
结果如下:
如果当join与interrupte方法如果彼此遇到,则会出现异常,但进程并没有结束,因为ThreadA还在继续运行,线程A并没有出现 异常,是正常状态下继续 执行。比如:
public class Demo09 { public static void main(String[] args) throws InterruptedException { Thread09_B t = new Thread09_B(); t.start(); Thread.sleep(10); Thread t2 = new Thread09_C(t); t2.start(); } } class Thread09_A extends Thread{ @Override public void run() { for (int i = 0; i < Integer.MAX_VALUE; i++) { // 耗时操作 String s = new String(); Math.random(); } } } class Thread09_B extends Thread{ @Override public void run() { try { Thread09_A t1 = new Thread09_A(); t1.start(); t1.join(); System.out.println("B线程正常结束"); } catch (InterruptedException e) { System.out.println("B线程异常结束"); e.printStackTrace(); } } } class Thread09_C extends Thread{ private Thread09_B t; public Thread09_C(Thread09_B t){ this.t = t; } @Override public void run() { t.interrupt(); } } 复制代码
结果如下: