Java多線程

Java多線程

一、程序 進程 線程

  1. 程序:指令集 靜態資源
  2. 進程:操作系統 調度程序 動態概念
  3. 線程:在進程內多條執行路徑

二、創建

Java中線程的創建常見有如三種基本形式

1、繼承Thread類,重寫該類的run方法

兔子類:

public class Rabbit extends Thread{
    @Override
    public void run() {
        for (int i = 0; i <= 100; i++) {
            System.out.println("兔子跑了"+i+"步");
        }
    }
}

烏龜類:

public class Tortoise extends Thread {
    @Override
    public void run() {
        for (int i = 0; i <= 100; i++) {
            System.out.println("烏龜跑了"+i+"步");
        }
    }
}

龜兔賽跑:

public class Game {
    public static void main(String[] args) {
        Rabbit rabbit = new Rabbit();
        Tortoise tortoise = new Tortoise();
        rabbit.start();
        tortoise.start();
    }
}

2、實現Runnable接口,並重寫該接口的run()方法。

該run()方法同樣是線程執行體。

步驟

  1. 創建Runnable實現類的實例。
  2. 並以此實例作爲Thread類的target來創建Thread對象,該Thread對象纔是真正的線程對象。
  3. Thread對象.start()

優勢

  1. 避免了單繼承的侷限性
  2. 便於共享資源 適合多個相同的程序代碼的線程去處理同一個資源
  3. 增加程序的健壯性,代碼可以被多個線程共享,代碼和數據獨立
  4. 線程池只能放入實現Runable或callable類線程,不能直接放入繼承Thread的類
public class Programmer implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 1000; i++) {
            System.out.println("一遍寫代碼一遍看視頻");
        }
    }
}

Thread 這裏使用的事靜態代理模式

  1. 真實角色 我們這個Programmer類
  2. 代理角色 Thread 類

兩者都實現了run方法,代理角色要持有真實角色的引用 new Thread(programmer)

public class Start {
    public static void main(String[] args) {
        Programmer programmer = new Programmer();
        Thread proxy = new Thread(programmer);
        proxy.start();
        for (int i = 0; i < 1000; i++) {
            System.out.println("一遍聊QQ");
        }
    }
}

3、通過Callable接口實現多線程

步驟

  1. 創建Callable實現類+重寫call
  2. 藉助調度服務ExecutorService,獲得Future對象
ExecutorService ser= Executors.newFixedThreadPool(2);
Future result = ser.submit(實現類對象)
  1. 獲取值 result.get()
  2. 停止服務ser.shutdownNow()

優勢

  1. 與實行Runnable相比, Callable功能更強大些
  2. 可以有返回值, 支持泛型的返回值
  3. 可以拋出異常

線程池

Java通過Executors提供四種線程池,分別爲:

  1. newCachedThreadPool
    創建一個可緩存線程池,如果線程池長度超過處理需要,可靈活回收空閒線程,若無可回收,則新建線程。
  2. newFixedThreadPool
    創建一個定長線程池,可控制線程最大併發數,超出的線程會在隊列中等待。
  3. newScheduledThreadPool
    創建一個定長線程池,支持定時及週期性任務執行。
  4. newSingleThreadExecutor
    創建一個單線程化的線程池,它只會用唯一的工作線程來執行任務,保證所有任務按照指定順序(FIFO, LIFO, 優先級)執行。

具體實現

Future接口
  • 可以對具體Runnable、 Callable任務的執行結果進行取消、 查詢是否完成、 獲取結果等。
public class Call {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //創建一個可重用固定線程數的線程池
        ExecutorService ser = Executors.newFixedThreadPool(2);
        Race tortoise = new Race("千年王八",1000L);
        Race rabbit = new Race("兔子",500L);
        //FutureTask 也可以瞭解一下
        Future<Integer> result = ser.submit(tortoise);
        Future<Integer> result2 = ser.submit(rabbit);
        Thread.sleep(2000);
        tortoise.setFlag(false);
        rabbit.setFlag(false);

        int num1 = result.get();
        int num2 = result2.get();
        System.out.println("烏龜跑了————>"+num1);
        System.out.println("兔子跑了————>"+num2);
        ser.shutdownNow();
    }
}

class Race implements Callable<Integer> {
    private String name;//名稱
    private long time;//延時時間
    private boolean flag = true;
    private int step = 0;

    public Race() {
    }
    public Race(String name) {
        this.name = name;
    }
    public Race(String name, long time) {
        this.name = name;
        this.time = time;
    }

    @Override
    public Integer call() throws Exception {
        while (flag){
            Thread.sleep(time);
            step++;
        }
        return step;
    }

    Getter Setter方法省略……
}
FutureTask實現類
  • FutrueTask是Futrue接口的唯一的實現類
  • FutureTask 同時實現了Runnable, Future接口。 它既可以作爲Runnable被線程執行, 又可以作爲Future得到Callable的返回值
    //第一種方式
    ExecutorService executor = Executors.newCachedThreadPool();
    Task task = new Task();
    FutureTask<Integer> futureTask = new FutureTask<Integer>(task);
    executor.submit(futureTask);
    executor.shutdown();
    //第二種方式,注意這種方式和第一種方式效果是類似的,只不過一個使用的是ExecutorService,一個使用的是Thread
    Task task = new Task();
    FutureTask<Integer> futureTask = new FutureTask<Integer>(task);
    Thread thread = new Thread(futureTask);
    thread.start();

三、線程狀態

在這裏插入圖片描述
後續待學習整理

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章