1. 程式人生 > >Java基礎之多執行緒之原理、實現方式及匿名內部類建立執行緒方法

Java基礎之多執行緒之原理、實現方式及匿名內部類建立執行緒方法

一、概念

程序:作業系統當中正在執行的一個程式。例如正在執行一個QQ。
執行緒:程序之內多工的執行單位。例如迅雷當中正在下載的多個電影。
JVM當中:棧(Stack)記憶體是執行緒獨立的,堆(Heap)記憶體是執行緒共享的。
(1)Java程式執行的時候至少有兩個執行緒:
1)主執行緒(main方法執行的所線上程)
2)垃圾回收執行緒(gc執行緒)
(2)Java當中的多執行緒採用搶佔式排程:
多個執行緒之間無規則來回搶CPU,誰搶到了誰執行,誰沒搶到活該,下次再搶。
無法精確控制多個執行緒之間來回切換的規律。

二、多執行緒原理

閱讀以下程式:

// 自定義實現類
public class MyThread extends Thread { @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println("小強-" + i); try { Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } } } } // main方法
public class Demo01Thread { public static void main(String[] args) { MyThread mt = new MyThread(); mt.start(); for (int i = 0; i < 100; i++) { System.out.println("旺財-" + i); try { Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } } } }

程式流程圖如下:
這裡寫圖片描述
執行緒開啟的記憶體圖如下:
這裡寫圖片描述

三、如何實現多執行緒的程式

  1. 繼承類:java.lang.Thread類。
    Thread類代表執行緒類,一個Thread物件就是一個執行緒,也就是一個任務執行的單位。
  2. 實現Runnable介面。
    :執行緒是作業系統當中極其寶貴的系統資源,一定要節省使用。

四、使用步驟

(一)繼承Thread類
1. 定義一個類,繼承Thread類。
2. 覆蓋重寫其中的run方法,用來指定執行緒任務內容。
public void run() {…}
3. 建立物件,呼叫.start()方法啟動執行緒。
:不要自己呼叫run,否則沒有多執行緒的效果。
tips:
1. 可以通過下面的方法來獲取當前執行緒的名稱:
String name = Thread.currentThread().getName();
執行緒的命名如果沒有指定,那麼將會預設使用Thread-0、Thread-1進行依次命名。
2. 在run()方法中如果出現了異常只能通過try-catch來捕捉,這是因為Thread並未繼承任何異常類,子類對異常的處理範圍又必須小於父類,所以無法throws異常。

// 自定義執行緒類,繼承Thread
public class MyThread extends Thread {

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("小強-" + i);
        }
    }
}
// main方法
public class Demo01Thread {

    public static void main(String[] args) {
        MyThread mt = new MyThread();
        mt.start();
    }

}

(二)實現Runnable介面
1. 定義一個類實現Runnable介面。
2. 覆蓋重寫run()方法,指定任務內容。
3. 建立Runnable物件作為Thread的構造引數。
4. 呼叫start()方法,啟動執行緒。

// 自定義實現類,實現Runnable介面
public class MyRunnableImpl implements Runnable {
    @Override
    public void run() {
        String name = Thread.currentThread().getName();
        for (int i = 1; i <= 100; i++) {
            System.out.println(name + " : " + i);
        }
    }
}
public class Demo04Runnable {

    public static void main(String[] args) {
        Runnable task = new MyRunnableImpl(); // 建立了Runnable實現類的物件。

        new Thread(task).start(); // 沒有定義執行緒名稱,自動分配名稱
        new Thread(task, "我的執行緒").start(); // 指定了自定義的執行緒名稱,用指定的。
    }

}

:推薦使用介面形式,實現Runnable介面比繼承Thread類所具有的優勢:
1. 適合多個相同的程式程式碼的執行緒去共享同一個資源。
2. 可以避免java中的單繼承的侷限性,但實現介面就沒有限制。
3. 增加程式的健壯性,實現解耦操作,程式碼可以被多個執行緒共享,程式碼和執行緒獨立。
4. 執行緒池只能放入實現Runable或Callable介面執行緒,不能直接放入繼承Thread的類。
5. Thread中功能很多,但Runnable中只有一個run()方法,使用起來更加簡單。

五、使用匿名內部類實現執行緒的建立

// 使用匿名內部類的方式實現Runnable介面,重新Runnable介面中的run方法:
public class NoNameInnerClassThread {
public static void main(String[] args) {
        // new Runnable(){
        // public void run(){
        // for (int i = 0; i < 20; i++) {
        // System.out.println("張宇:"+i);
        // }
        // }
        // }; //‐‐‐這個整體 相當於new MyRunnable()
        Runnable r = new Runnable(){
            public void run(){
                for (int i = 0; i < 20; i++) {
                System.out.println("張宇:"+i);
                }
            }
        };
        new Thread(r).start();
        for (int i = 0; i < 20; i++) {
            System.out.println("費玉清:"+i);
        }
    }
}

匿名類的三種使用場景:
1. 可以適用於介面,覆蓋重寫抽象方法。
2. 也可以適用於抽象類,覆蓋重寫抽象方法。
3. 也可以適用於普通類,只要不是final的,就能覆蓋重寫。