java基礎-多線程初步瞭解

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

學習多線程,首先要了解多線程。有不少概念仍是要了解一下java

對「程」的基本認識

推薦連接:java線程基礎的一篇博客,很詳細
bash

推薦連接:線程和進程的區別,很詳細(若是這個看了,下面的幾段文字能夠過,抄的)多線程

有兩種程,進程和線程併發

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

線程,線程是進程的一部分,一個沒有線程的進程能夠被看做是單線程。線程有時又被成爲輕量級進程,也是CPU調度的一個基本單位學習

線程的改變只表明CPU的執行過程的改變,而沒有發生進程所擁有的資源變化。除了CPU以外,計算機的軟硬件資源分配與線程無關,線程只能共享它所屬進程的資源。this

與進程控制表和PCB類似,每一個線程也有本身的線程控制表TCB,而這個TCB中所保存的線程狀態則比PCB表少得多,這些信息主要是相關指針用堆棧(系統棧和用戶棧),寄存器中的狀態數據。spa

進程擁有一個完整的虛擬機地址空間,不依賴於線程而獨立存在;反之,線程是進程的一部分,沒有本身的地址空間,與進程內的其餘線程一塊兒共享給該進程的全部資源。線程

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()喚醒鎖,再次走當上面剛剛說的堵塞中。這裏就基本瞭解了線程的運行狀態

這是上面我推薦的博客上面的


簡單看一下源碼

下面是基本的使用,線程有兩個中重要的類,一個是抽象類,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

相關文章
相關標籤/搜索