首页 > 代码库 > java多线程基本概述(七)——join()方法
java多线程基本概述(七)——join()方法
在很多情况下,主线程创建并启动子线程,如果子线程中有大量的耗时运算,主线程将早于子线程结束,如果想让主线程等待子线程结束后再结束,那么我们可以使用join()方法。调用join()方法的意思是当前线程使调用了该方法的线程执行完成然后再执行自己本身。api文档如下:
public final void join(long millis, int nanos) throws InterruptedException Waits at most millis milliseconds plus nanos nanoseconds for this thread to die. This implementation uses a loop of this.wait calls conditioned on this.isAlive. As a thread terminates the this.notifyAll method is invoked. It is recommended that applications not use wait, notify, or notifyAll on Thread instances. Parameters: millis - the time to wait in milliseconds nanos - 0-999999 additional nanoseconds to wait Throws: IllegalArgumentException - if the value of millis is negative, or the value of nanos is not in the range 0-999999 InterruptedException - if any thread has interrupted the current thread. The interrupted status of the current thread is cleared when this exception is thrown
简单翻译如下:调用该方法的线程会等待millils+nanos的时间,直到该线程执行完(调用该方法的Thread.isAlive()方法返回false时)。该方法的实现是使用循环判断该线程isAlive()方法,如果为true,那么就调用wait()方法进行等待。当线程结束时,notifyAll()方法被调用。如果调用join()后再调用notify()/notifyAll()则可能会时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; } } }
例子:
package soarhu; class Service{ void readMethod(){ try { for (int i = 0; i < 5; i++) { System.out.println(i); } }catch (Exception e){ e.printStackTrace(); } } } public class Test { public static void main(String[] args) throws Exception { Service o = new Service(); new Thread(){ @Override public void run() { o.readMethod(); } }.start(); System.out.println("main......."); } }
输出结果:
main....... 0 1 2 3 4 Process finished with exit code 0
结果分析:可知主线程方法先被执行完毕。如果要使子线程先执行完,然后执行主线程。那么可以调用join()方法。
package soarhu; class Service{ void readMethod(){ try { for (int i = 0; i < 25; i++) { Thread.yield(); System.out.println(i+" "+Thread.currentThread().getName()); } }catch (Exception e){ e.printStackTrace(); } } } public class Test { public static void main(String[] args) throws Exception { Service o = new Service(); Thread t = new Thread(){ @Override public void run() { o.readMethod(); } }; t.start(); t.join(); for (int i = 0; i < 10; i++) { System.out.println("main......."+i); } } }
输出结果:
0 Thread-0 1 Thread-0 2 Thread-0 3 Thread-0 4 Thread-0 5 Thread-0 6 Thread-0 7 Thread-0 8 Thread-0 9 Thread-0 10 Thread-0 11 Thread-0 12 Thread-0 13 Thread-0 14 Thread-0 15 Thread-0 16 Thread-0 17 Thread-0 18 Thread-0 19 Thread-0 20 Thread-0 21 Thread-0 22 Thread-0 23 Thread-0 24 Thread-0 main.......0 main.......1 main.......2 main.......3 main.......4 main.......5 main.......6 main.......7 main.......8 main.......9 Process finished with exit code 0
可知确实是等待子线程执行完后才执行主线程。我们不用join()也可以参考api源码来实现join().如下:
public class Test { public static void main(String[] args) throws Exception { Service o = new Service(); Thread t = new Thread() { @Override public void run() { o.readMethod(); } }; t.start(); //t.join(); synchronized (t) { do { t.wait(); } while (t.isAlive()); } for (int i = 0; i < 10; i++) { Thread.yield(); System.out.println("main......." + i); } } }
输出结果:
0 Thread-0 1 Thread-0 2 Thread-0 3 Thread-0 4 Thread-0 5 Thread-0 6 Thread-0 7 Thread-0 8 Thread-0 9 Thread-0 10 Thread-0 11 Thread-0 12 Thread-0 13 Thread-0 14 Thread-0 15 Thread-0 16 Thread-0 17 Thread-0 18 Thread-0 19 Thread-0 20 Thread-0 21 Thread-0 22 Thread-0 23 Thread-0 24 Thread-0 main.......0 main.......1 main.......2 main.......3 main.......4 main.......5 main.......6 main.......7 main.......8 main.......9 Process finished with exit code 0
可见join()方法的实现方式很简单,就是加一个同步方法,再内部循环判断该线程是否结束,如果未结束,则再jon()这个地方一致阻塞,导致下面的代码不能被执行,如果在调用join()方法后,再调用该线程的wait()方法则会发生死锁,调用notify()则可能发生死锁或者join()失效。例子如下:
package soarhu; import java.util.concurrent.TimeUnit; class Service { void readMethod() { try { for (int i = 0; i < 25; i++) { TimeUnit.MILLISECONDS.sleep(300); Thread.yield(); while (i==5){ //1 line synchronized (this){ //wait(); // 发生死锁 this.notifyAll(); } } System.out.println(i + " " + Thread.currentThread().getName()); } } catch (Exception e) { e.printStackTrace(); } } } public class Test { public static void main(String[] args) { Service o = new Service(); Thread t = new Thread() { @Override public void run() { o.readMethod(); } }; t.start(); try { t.join(); for (int i = 0; i < 10; i++) { System.out.println("main......." + i); } } catch (InterruptedException e) { e.printStackTrace(); } } }
输出结果:死锁
0 Thread-0 1 Thread-0 2 Thread-0 3 Thread-0 4 Thread-0
由于join()内部是用的wait()方法,那么也可能会抛出中断异常,举例如下:
package soarhu; import java.util.concurrent.TimeUnit; class Service extends Thread { @Override public void run() { try { for (int i = 0; i < 25; i++) { TimeUnit.MILLISECONDS.sleep(300); Thread.yield(); if (i==5){ this.interrupt(); } System.out.println(i + " " + Thread.currentThread().getName()); } } catch (Exception e) { e.printStackTrace(); } } } public class Test { public static void main(String[] args) { Service o = new Service(); o.start(); try { o.join(); System.out.println("isAlive? "+o.isAlive()); for (int i = 0; i < 10; i++) { System.out.println("main......." + i); } } catch (InterruptedException e) { e.printStackTrace(); } } }
输出结果:
0 Thread-0 1 Thread-0 2 Thread-0 3 Thread-0 4 Thread-0 java.lang.InterruptedException: sleep interrupted at java.lang.Thread.sleep(Native Method) at java.lang.Thread.sleep(Thread.java:340) 5 Thread-0 at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386) isAlive? false at soarhu.Service.run(Test.java:12) main.......0 main.......1 main.......2 main.......3 main.......4 main.......5 main.......6 main.......7 main.......8 main.......9 Process finished with exit code 0
java多线程基本概述(七)——join()方法
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。