JavaSE基礎系列之執行緒

llovesoftware 發表於 2020-10-18

一.啟動執行緒的方式  

1.自定義類繼承Thread類並重寫run方法,然後建立該類的物件呼叫start方法。

格式:

   Thread t1 = new SubThreadRun();  // 宣告Thread型別的引用指向子類型別的物件(建立自定義類  

   SubThrea dRun 實現Thread介面)      

  t1.start();

2.自定義類實現Runnable介面並重寫run方法,建立該類的物件作為實參來構造Thread             型別的物件,然後使用Thread型別的物件呼叫start方法。   

格式:

  TestRunnableRun srr = new TestRunnableRun (); // 自定義類TestRunnableRun實現Runnable介面類的run方法。

   Thread t1 = new Thread(srr);   

   t1.start();

3. 實現 Callable 介面,使用 FutureTask 類建立執行緒

  

import java.util.concurrent.Callable;

import java.util.concurrent.ExecutionException;

import java.util.concurrent.FutureTask;

public class ThreadCallableTest implements Callable {

    @Override

    public Object call() throws Exception {

        // 計算 ~ 10000之間的累加和並列印返回

        int sum = 0;

        for (int i = 1; i <= 100; i++) {

            sum += i;

        }

        System.out.println("計算的累加和是:" + sum); // 50005000

        return sum;

    }

    public static void main(String[] args) {

        ThreadCallableTest tct = new ThreadCallableTest();

        FutureTask ft = new FutureTask(tct);

        Thread t1 = new Thread(ft);

        t1.start();

        Object obj = null;

        try {

            obj = ft.get();

        } catch (InterruptedException e) {

            e.printStackTrace();

        } catch (ExecutionException e) {

            e.printStackTrace();

        }

        System.out.println("執行緒處理方法的返回值是:" + obj); // 50005000

    }

}

4.通過建立執行緒池啟動執行緒  

  格式:

        // 1.建立一個執行緒池

        ExecutorService executorService = Executors.newFixedThreadPool(10);

        // 2.向執行緒池中佈置任務(自定義類實現Callable,重寫介面中的call()方法,然後例項化類作為引數向執行緒池中佈置任務 )

        executorService.submit(new ThreadCallableTest());

        // 3.關閉執行緒池

        executorService.shutdown();

二.執行緒的生命週期

JavaSE基礎系列之執行緒

1.新建狀態 - 使用new關鍵字建立之後進入的狀態,此時執行緒並沒有開始執行。

2.就緒狀態 - 呼叫start方法後進入的狀態,此時執行緒還是沒有開始執行。

3.執行狀態 - 使用執行緒排程器呼叫該執行緒後進入的狀態,此時執行緒開始執行,當執行緒的時間片執行完畢後任務沒有完成時回到就緒狀態。

4.消亡狀態 - 當執行緒的任務執行完成後進入的狀態,此時執行緒已經終止。

5.阻塞狀態 - 當執行緒執行的過程中發生了阻塞事件進入的狀態,如:sleep方法。阻塞狀態解除後進入就緒狀態。

三.執行緒同步機制

1.基本概念

    當多個執行緒同時訪問同一種共享資源時,可能會造成資料的覆蓋等不一致性問題,此時就需要對線 程之間進行通訊和協調,該機制就叫做執行緒的同步機制。 多個執行緒併發讀寫同一個臨界資源時會發生執行緒併發安全問題。

非同步操作:多執行緒併發的操作,各自獨立執行。 

同步操作:多執行緒序列的操作,先後執行的順序。

  1. 解決方案

由程式結果可知:當兩個執行緒同時對同一個賬戶進行取款時,導致最終的賬戶餘額不合理。 引發原因:執行緒一執行取款時還沒來得及將取款後的餘額寫入後臺,執行緒二就已經開始取款。 解決方案:讓執行緒一執行完畢取款操作後,再讓執行緒二執行即可,將執行緒的併發操作改為序列操 作。 經驗分享:在以後的開發儘量減少序列操作的範圍,從而提高效率。

  1. 實現方式

  在Java語言中使用synchronized關鍵字來實現同步/物件鎖機制從而保證執行緒執行的原子性,具體 方式如下: 使用同步程式碼塊的方式實現部分程式碼的鎖定,格式如下: synchronized(類型別的引用) { 編寫所有需要鎖定的程式碼; } 使用同步方法的方式實現所有程式碼的鎖定。 直接使用synchronized關鍵字來修飾整個方法即可 該方式等價於: synchronized(this) { 整個方法體的程式碼 }

  1. 靜態方法的鎖定

當我們對一個靜態方法加鎖,如: public synchronized static void xxx(){….} 那麼該方法鎖的物件是類物件。每個類都有唯一的一個類物件。獲取類物件的方式:類名.class。 靜態方法與非靜態方法同時使用了synchronized後它們之間是非互斥關係的。

  1. 注意事項

 使用synchronized保證執行緒同步應當注意: 多個需要同步的執行緒在訪問同步塊時,看到的應該是同一個鎖物件引用。 在使用同步塊時應當儘量減少同步範圍以提高併發的執行效率。

四.執行緒池  

  什麼是執行緒池?

  執行緒池就是建立若干個可執行的執行緒放入一個池(容器)中,有任務需要處理時.會提交到執行緒池的任務佇列,處理完之後執行緒不會被銷燬,而是仍然線上程池中等待下一個任務。

  為什麼要使用執行緒池?

因為java中建立一個執行緒,需要呼叫作業系統核心的API,作業系統要為執行緒分配一系列的資源,成本高,所以執行緒是一個重量級的物件,應該避免頻繁建立和銷燬。使用執行緒池就能很好地避免頻繁建立和銷燬。