java基礎-多執行緒初步瞭解

楚棠發表於2019-03-05

把java基礎擼一邊,從簡單的開始

學習多執行緒,首先要了解多執行緒。有很多概念還是要了解一下

對“程”的基本認識

推薦連結:java執行緒基礎的一篇部落格,很詳細

推薦連結:執行緒和程式的區別,很詳細(如果這個看了,下面的幾段文字可以過,抄的)

有兩種程,程式和執行緒

程式,是併發執行的程式在執行過程中分配和管理資源的基本單位,是一個動態概念,競爭計算機系統資源的基本單位。

執行緒,執行緒是程式的一部分,一個沒有執行緒的程式可以被看作是單執行緒。執行緒有時又被成為輕量級程式,也是CPU排程的一個基本單位

執行緒的改變只代表CPU的執行過程的改變,而沒有發生程式所擁有的資源變化。除了CPU之外,計算機的軟硬體資源分配與執行緒無關,執行緒只能共享它所屬程式的資源。

與程式控制表和PCB相似,每個執行緒也有自己的執行緒控制表TCB,而這個TCB中所儲存的執行緒狀態則比PCB表少得多,這些資訊主要是相關指標用堆疊(系統棧和使用者棧),暫存器中的狀態資料。

程式擁有一個完整的虛擬機器地址空間,不依賴於執行緒而獨立存在;反之,執行緒是程式的一部分,沒有自己的地址空間,與程式內的其他執行緒一起共享給該程式的所有資源。

java執行緒生命週期圖(這圖是我照著畫的):

java基礎-多執行緒初步瞭解

如果有興趣的話,也可以畫畫。

以下是我亂逼逼,自己的認識。最好看官方的

執行緒的生命狀態:新建狀態,就緒狀態,執行狀態,阻塞狀態,死亡狀態

阻塞狀態的時候,有兩個定義,等待,和堵塞。等待:(理解)執行緒要進入的CPU被其他執行緒佔用,服務執行該執行緒的任務。阻塞狀態,程式碼notify()方法,或者說,除系統通知外叫醒這個執行緒的是等待。而堵塞是系統叫醒,比如sleep()。睡眠玩時間之後,系統會通知這個執行緒結束了。

Thread物件例項化後執行start()方法並沒有馬上去執行run()方法,而是在在Runnable就緒狀態去搶奪CPU資源開始執行。起跑100米也要準備以下start()後就是需要準的強制CPU資源的那一瞬間,到了Running執行狀態後如果執行完畢或者有異常退出,這個執行緒也就執行完畢Dead死亡了。

但還有可能在執行過程中出現堵塞狀況,比如sleep()睡眠,join()方法就會出現堵塞,當sleep結束或者join終端,I/O完成的時候會重新到Runnable準備去搶佔CPU資源,而正在執行的Running的執行緒在yield的時候就與禮讓CPU資源 進入Runnable狀態

在Running狀態的時候synchronize會進入鎖,這個時候會等待處理一下。當同步鎖被釋放的時候會進入Runnable再去搶佔資源

在Running狀態的時候synchronize狀態後wait()釋放鎖等待再到notify()喚醒鎖,再次走當上面剛剛說的堵塞中。這裡就基本瞭解了執行緒的執行狀態

這是上面我推薦的部落格上面的

java基礎-多執行緒初步瞭解

簡單看一下原始碼

下面是基本的使用,執行緒有兩個中重要的類,一個是抽象類,Runnable,一個是Runnable實現類Thread。使用執行緒的時候一般是new Thread().start();這樣就可以開啟一個執行緒

還有就是實現Runnable的類,比如A實現了Runnable類,

A a = new A;

new Thread(a).start();這樣也可以開啟一個執行緒。兩者的實現不同來自於對Thread類不同的構造方法不同

public Thread() {
    init(null, null, "Thread-" + nextThreadNum(), 0);
}

public Thread(Runnable target) {
    init(null, target, "Thread-" + nextThreadNum(), 0);
}複製程式碼

在來看看Runnable類

public interface Runnable {
  
    public abstract void run();
}複製程式碼

run()方法裡面就是這個執行緒的執行內容。

再來看看Thread的start()方法

public synchronized void start() {
  
    if (threadStatus != 0)
        throw new IllegalThreadStateException();

    group.add(this);

    boolean started = false;
    try {
        start0();
        started = true;
    } finally {
        try {
            if (!started) {
                group.threadStartFailed(this);
            }
        } catch (Throwable ignore) {

        }
    }
}

private native void start0();複製程式碼

看到native就知道是去呼叫C程式碼

start0()方法會新執行一個執行緒,新執行緒會呼叫run()方法。

public void run() {
    if (target != null) {
        target.run();
    }
}複製程式碼

這樣一來就可以理清楚繼承Thread類和實現Runnable類兩種基本用法的區別

通過繼承Thread類的需要去實現Thread。因為在構建方法中init方法是傳遞的null去賦值的。如果是建立傳遞了Runnable中,是傳遞過去。並且賦值,這樣再run()方法中判斷了target()並且執行了該實現Runnable類的run()方法

基本實現

知道這個程式碼背景,就對執行緒的使用有了一個概念。

public class Demo1 extends Thread{

    public Demo1(String name){
        super(name);
    }

    @Override
    public void run() {
        while (!interrupted()) {
            System.out.println("執行緒 :"+getName());
        }
    }

    public static void main(String[] age){
        Demo1 a = new Demo1("A");
        a.start();
    }
}複製程式碼

繼承Thread的實現

public class Demo2 implements Runnable {

    public static void main(String[] age){
        Demo2 demo2 = new Demo2();
        Thread thread = new Thread(demo2);
        thread.start();
    }


    public void run(){
        while (true){
            System.out.println("thread running ...");
        }
    }
}複製程式碼

實現抽象類的Runnable


相關文章