Java—-多線程詳解(二)

來源:互聯網
上載者:User

3、線程狀態

      線程存在多種狀態,包括新狀態、可運行狀態、運行狀態、等待/被阻塞/睡眠/監控/掛起狀態和死狀態5中狀態。

      1)、新狀態

      新狀態是指線程執行個體化後,但start方法還沒有在該線程上被調用時所處的狀態。它還沒有達到準備啟動並執行狀態,更不是一個執行線程。

      2)、可運行狀態

      Start()方法啟動後,線程由新狀態進入可運行狀態。可運行狀態就是準備好,可以運行但還沒有啟動並執行狀態。

      不但stat()方法可以進入運行狀態,而且從等待/被阻塞/睡眠/監控/掛起狀態也可以進入可運行狀態。如調用sleep()方法結束後,調用yield(0方法結束後所作用的線程都進入可運行狀態。

      可運行狀態也可以說是CPU選擇線程的狀態。所有的線程不分主次、前後,只要處於可運行狀態都有可能被CPU選中運行,當然有可能本線程處於可運行狀態,但是很長時間不運行它,這個是一種特殊情況。還有其中情況就是總是運行一個線程,如在一個線程中調用yield()方法後進入可運行狀態,但是下面啟動並執行還是這個線程。

      3)、運行狀態

就是當前執行線程所處的狀態,它可以轉入可運行狀態和等待/被阻塞/失眠/監控/掛起狀態,但是只能從可運行狀態進入運行狀態。

      4)、等待/被阻塞/睡眠/監控/掛起狀態

      等待/被阻塞/睡眠/監控/掛起狀態很複雜,它是很多狀態的集合體,但是都起到從運行狀態到可運行狀態的中介作用。處於運行狀態的線程由於某種原因不能繼續運行,例如調用sleep()方法、被調用join()方法,此線程就會由運行狀態進入等待/被阻塞/睡眠/監控/掛起狀態。而當sleep()方法結束後或調用join()方法的線程結束後,該線程就又進入可運行狀態。

      進入等待/被阻塞/睡眠/監控/掛起狀態的方法除了sleep()、yield()方法和join()方法外,還有suspend()方法,它是指讓一個線程把另一個線程掛起。

      5)、死狀態

      當線程中的run()方法完成之後,線程就進入了死狀態。對處於一個死狀態的線程帶哦用start()方法會發生異常。

4、線程的調度

      線程發送器是JVM中的一部分,它決定在任意指定的時刻應該運行哪個線程,並吧線程帶出運行狀態。線程的調度定義了java運行環境如何交換任務以及如何選擇下一個即將被執行的任務。對線程進行調度又通過優先順序、sleep()、yield()、join()方法來完成。在前面說過CPU對線程的選擇是不確定的,所以通過調度知識讓線程按照某種方式運行,而不能徹底規定它。

      1)、優先順序

      用來判定何時允許某個線程運行。理論上優先順序高的線程比優先順序低的線程可獲得更多的CPU時間。實際上獲得CPU時間長度與很多因素有關,不能僅靠優先順序來判斷。設計線程的優先順序使用setPriority(int level)方法來設定。在level值中,用MIN_PRIORITY來表示優先順序最小1;用MAX_PRIORITY來表示優先順序最大10;線程的預設優先順序為5即NORM_PRIORITY。

      獲得當前線程的優先順序的方法是getPriority(),其一般形式為getPriority()。

      看下面應用優先順序的程式,它通過執行迴圈、記錄次數來表現出優先順序的高低:

 

public class test{    public static void main(String[] str) {       Thread.currentThread().setPriority(Thread.MAX_PRIORITY);        MyThread t1 = newMyThread(Thread.NORM_PRIORITY + 2);        MyThread t2 = newMyThread(Thread.NORM_PRIORITY - 2);        t1.start();        t2.start();        try {            Thread.sleep(1000);        } catch (Exception e) {        }        t1.stop();        t2.stop();        try {            t1.t.join();            t2.t.join();        } catch (Exception e) {        }        System.out.println("低優先順序線程" +t2.click);        System.out.println("高優先順序線程" +t1.click);    }}class MyThread implementsRunnable{    int click = 0;    Thread t;    private volatile boolean running = true;    public MyThread(int p){        t = new Thread(this);        t.setPriority(p);    }    @Override    public void run() {        while (running) {                       click++;        }    }    public void stop() {        running = false;    }    public void start() {        t.start();    }}

 

 

      該程式的輸出結果與CPU有關,運行本程式還能看出CPU的速度。

      2)、sleep睡眠方法

      線程sleep()是一個靜態方法,它強制線程進入睡眠狀態。線上程中使用sleep()方法是非常必要的,它起到使線程停頓的作用。Sleep()方法可能拋出InterruptedException異常,在使用sleep()方法時一定要進行異常處理。

 

public class test{    public static void main(String[] str) {        MyThread1 t1 = new MyThread1();        MyThread2 t2 = new MyThread2();        MyThread3 t3 = new MyThread3();        t1.start();        t2.start();        t3.start();    }} class MyThread1 extendsThread{    @Override    public void run() {        for (int i = 0; i < 20; i++) {            System.out.print("●");            try {                Thread.sleep(1000);            } catch (Exception e) {                System.err.println("異常:" + e);            }        }    }} class MyThread2 extendsThread{    @Override    public void run() {        for (int i = 0; i < 20; i++) {            System.out.print("■");            try {                Thread.sleep(1000);            } catch (Exception e) {                System.err.println("異常:" + e);            }        }    }} class MyThread3 extendsThread{    @Override    public void run() {        for (int i = 0; i < 20; i++) {            System.out.print("▲");            try {                Thread.sleep(1000);            } catch (Exception e) {                System.err.println("異常:" + e);            }        }    }}

 

 

      我們可以看到運行結果還是不完全確定的,sleep()方法也只是讓每個線程都有啟動並執行機會。

      3)、join加入方法

      Join()方法使一個線程1跟在當前啟動並執行線程2的後面運行,當線程1運行完後再繼續運行線程2。我們先來看一個例子:

 

public class test{    public static void main(String[] str) {        MyThread1 t1 = new MyThread1();        MyThread2 t2 = new MyThread2();        MyThread3 t3 = new MyThread3();        t2.mt1 = t1;        t1.start();        t2.start();        t3.start();    }} class MyThread1 extendsThread{    @Override    public void run() {        for (int i = 0; i < 20; i++) {            System.out.println("●");            try {                Thread.sleep(5000);            } catch (Exception e) {                System.err.println("異常:" + e);            }        }    }} class MyThread2 extendsThread{    public MyThread1 mt1;    @Override    public void run() {        for (int i = 0; i < 20; i++) {            System.out.println("■");            try {                Thread.sleep(5000);            } catch (Exception e) {                System.err.println("異常:" + e);            }            if (i == 10) {                try {                    mt1.join();                } catch (Exception e) {                    System.err.println("異常:" + e);                }            }        }    }} class MyThread3 extendsThread{    @Override    public void run() {        for (int i = 0; i < 20; i++) {            System.out.println("▲");            try {                Thread.sleep(5000);            } catch (Exception e) {                System.err.println("異常:" + e);            }        }    }}

 

 

      我們可以看到運行結果為:

      ●▲■●■▲▲●■▲●■▲■●●▲■●■▲●■▲■▲●■●▲▲●■● (i=10) ▲▲●▲●▲●▲●▲●▲●●▲●▲■■■■■■■■■成功構建 (總時間: 29 秒)

      當i = 10後,我們看到只列印出三角和實心圓,即線程t1和t3,當t1運行結束後,我們看到又列印出了正放心,即t2。

      4)、yield讓步方法

      yield()方法使當前啟動並執行線程回到可運行狀態,狀態的問題將在第五小節講到。Yield()方法的作用是讓有相同優先順序的線程獲得運行機會。yield()方法通常被稱為讓步方法,但它往往達不到讓步的目的,因為它只是讓當前線程回到可啟動並執行狀態,很可能啟動並執行線程又會是這一個。下面的例子使用預設優先順序講解yield()方法:

 

public class test{    public static void main(String[] str) {        MyThread1 t1 = new MyThread1();        MyThread2 t2 = new MyThread2();        MyThread3 t3 = new MyThread3();        t1.start();        t2.start();        t3.start();    }} class MyThread1 extendsThread{    @Override    public void run() {        for (int i = 0; i < 20; i++) {            System.out.print("●");            Thread.yield();        }    }} class MyThread2 extendsThread{    @Override    public void run() {        for (int i = 0; i < 20; i++) {            System.out.print("■");            Thread.yield();        }    }} class MyThread3 extendsThread{    @Override    public void run() {        for (int i = 0; i < 20; i++) {            System.out.print("▲");        }    }}

 

 

      我們對t1和t2執行yield()方法,執行結果會先列印出一連串的三角形,即t3。但讓步沒有完全成功,在三角形中仍然還有正方形和圓形:

      ■●▲▲▲▲▲▲▲●■●▲▲■▲▲▲▲▲▲▲▲▲▲▲●■■●■●■●●■●●■●●●■●■●■●■●■●■●■●■■■■成功構建 (總時間: 0 秒)

 

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.