天天看點

了解Java中的線程//用Thread的子類建立線程

Java中的線程

Java語言的一大特點就是内置了對多線程的支援.多線程是指同時存在幾個執行體,按幾條不同的執行線索共同工作的情況.

多線程的存在使得能夠友善地開發出能同時處理多個任務的應用程式,其中可能會使我們産生一種錯覺就是以為幾個事件是同時發生一樣,實際上不是的,這是由于Java快速地從一個線程切換到另一個線程而造成的

從下面的代碼看出是有問題的,兩個死循環實質上隻能執行第一個,第二個循環是永遠不會執行的

但是通過引入兩個線程的話,第二個循環就有機會被執行

public class Example15_1 {
    public static void main(String[] args) {
        while(true){
            System.out.println("hello");
        }
        while(true){	//不會執行
            System.out.println("hi");
        }
    }
}
           

程式/程序/線程

首相了解程式

程式是一段靜态的代碼,他是應用軟體執行的藍本

而後了解程序

程序是程式的一次動态執行過程,它對應了從代碼加載,執行至執行完畢的一個完整過程,這個過程也是程序本身從産生,發展至消忙的過程

最後到線程

線程就是比程序更小的執行機關

Java的多線程就是在作業系統每次分時給Java程式一個時間片的CPU時間内,在若幹個獨立的可控制的線程之間進行切換。如果機器有多個CPU處理器,那麼JVM就能充分利用這些CPU,使得Java程式在同一時刻能獲得多個時間片,Java程式就可以獲得真實的線程并發執行效果。

線程的狀态與生命周期

Java語言使用

Thread類

及其子類的對象來表示線程,Thread提供

getState()

方法傳回枚舉類型Thread.

下列就是枚舉常量

  • 建立狀态(NEW)

    建立的線程對象就是這種狀态,此時它已經有了資源以及記憶體空間,沒有調用

    start()

    方法的線程也是處于這種狀态
  • 可運作狀态(RUNNABLE)

    處于NEW狀态的線程一旦調用start()方法就會進入RUNNABLE狀态,進入此狀态JVM就會發現有一個新的程序在排隊等待切換了,

    如果該線程是Thread的子類,那麼必須重寫父類中的

    run()

    方法,run()方法規定了該線程的使命
  • 中斷狀态(BLOCKED / WAITING / TIMED_WAITING)

    當RUNNABLE狀态的線程讓出CPU使用權是就會使得狀态變為BLOCKED狀态 //相當于遇到突發情況就停下來了

    當線程使用CPU資源期間執行了sleep(int millsecond)方法後就會進入TIMED_WAITING狀态 ,當經過millsecond秒後再次進入RUNNABLE狀态 //相當于等待一個紅燈

    當線程調用wait()方法後就會進入WAITING狀态,必須有線程調用

    notif()

    方法通知它才會再次RUNNING
  • 死亡狀态(TERMINATED)

    一個線程執行完run()方法後進入TERMINATED狀态

需要注意的是隻有處于NEW狀态的線程才能調用start()方法,否則就會出現異常

//

線程的調用與優先級

處于就緒狀态的線程首先進入就緒隊列等待CPU資源,同一時刻在排隊的可能有多個

這時候Java虛拟機中的線程排程器負責管理線程,排程器把線程分為10級,分别用Thread類中的類常量來表示,每個Java線程優先級都為常數1-10 表示,沒有明确規定的話每個線程都是5級,但可以線程可以通過

setPriority(int grade)

方法來設定優先級,需要注意的是有些系統隻能識别1,5,10,三個級别

在實際程式設計中不提倡使用線程的優先級來保證算法的正确執行

用Thread的子類建立線程

在編寫Thread類的子類是,需要重寫父類的

run()

方法,其目的規定線程的具體操作,否則線程不知道幹什麼,run()方法在父類中是沒有任何語句的

線程中有

setName(String str)

方法設定線程的名稱

通過

getName()

方法可以擷取線程的名稱

通過例子來體會一下

class Person extends Thread {    //建立一個線程的子類
    StringBuffer stringBuffer;

    Person() {
    }

    Person(String name, StringBuffer stringBuffer) {
        setName(name);  //線程中的方法setName()設定線程的名稱
        this.stringBuffer = stringBuffer;
    }

    @Override
    public void run() {
        for (int i = 0; i < 4; i++) {
            getName();  //擷取線程中的名稱
            stringBuffer.append(getName() + ",");
            System.out.println("我是" + getName() + ",字元串為:" + stringBuffer);
            try {
                Thread.sleep(200);  //延遲0.2秒
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

public class Example15_1 {
    public static void main(String[] args) {
        StringBuffer stringBuffer = new StringBuffer(); //共享線程str
        Person hong = new Person("小紅", stringBuffer);
        Person ming = new Person("小明", stringBuffer);
        hong.start();   //開始線程
        ming.start();
    }
}
           

運作結果(每一次運作的結果都不一樣,因為不知道線程每次都先将CPU分給誰)

C:\Users\Administrator\.IntelliJIdea2019.3\config\jdbc-drivers\MySQL Connector\J 8\8.0.15\mysql-connector-java-8.0.15.jar;C:\Users\Administrator\.IntelliJIdea2019.3\config\jdbc-drivers\Apache Derby\10.14.1.0\derby-10.14.1.0.jar" Chapter_15.Part_1.Example15_1
我是小紅,字元串為:小明,小紅,
我是小明,字元串為:小明,小紅,
我是小紅,字元串為:小明,小紅,小紅,
我是小明,字元串為:小明,小紅,小紅,小明,
我是小明,字元串為:小明,小紅,小紅,小明,小明,
我是小紅,字元串為:小明,小紅,小紅,小明,小明,小紅,
我是小明,字元串為:小明,小紅,小紅,小明,小明,小紅,小明,小紅,
我是小紅,字元串為:小明,小紅,小紅,小明,小明,小紅,小明,小紅,

程序已結束,退出代碼 0
           

CET4P195

  • commence
  • collaborate
  • triple
  • doom
  • fluctuate
  • masterpiece
  • strive
  • narrate
  • gender
  • curb
  • expressway
  • irrational
  • betray
  • counterpart
  • ballot