java多線程基本概述(七)——join()方法

來源:互聯網
上載者:User

標籤:end   exce   時間   row   argument   art   comm   ring   lang   

在很多情況下,主線程建立並啟動子線程,如果子線程中有大量的耗時運算,主線程將早於子線程結束,如果想讓主線程等待子線程結束後再結束,那麼我們可以使用join()方法。調用join()方法的意思是當前線程使調用了該方法的線程執行完成然後再執行自己本身。api文檔如下:

public final void join(long millis,        int nanos)                throws InterruptedExceptionWaits 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 millisecondsnanos - 0-999999 additional nanoseconds to waitThrows:IllegalArgumentException - if the value of millis is negative, or the value of nanos is not in the range 0-999999InterruptedException - 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.......01234Process 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-01 Thread-02 Thread-03 Thread-04 Thread-05 Thread-06 Thread-07 Thread-08 Thread-09 Thread-010 Thread-011 Thread-012 Thread-013 Thread-014 Thread-015 Thread-016 Thread-017 Thread-018 Thread-019 Thread-020 Thread-021 Thread-022 Thread-023 Thread-024 Thread-0main.......0main.......1main.......2main.......3main.......4main.......5main.......6main.......7main.......8main.......9Process 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-01 Thread-02 Thread-03 Thread-04 Thread-05 Thread-06 Thread-07 Thread-08 Thread-09 Thread-010 Thread-011 Thread-012 Thread-013 Thread-014 Thread-015 Thread-016 Thread-017 Thread-018 Thread-019 Thread-020 Thread-021 Thread-022 Thread-023 Thread-024 Thread-0main.......0main.......1main.......2main.......3main.......4main.......5main.......6main.......7main.......8main.......9Process 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-01 Thread-02 Thread-03 Thread-04 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-01 Thread-02 Thread-03 Thread-04 Thread-0java.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.......0main.......1main.......2main.......3main.......4main.......5main.......6main.......7main.......8main.......9Process finished with exit code 0

 

java多線程基本概述(七)——join()方法

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.