Java基礎:多線程(1)--線程的概述、創建線程的方式、線程的多種狀態、線程常用的方法

一、線程的概述

進程:正在運行的程序,負責了這個程序的內存空間分配,代表了內存中的執行區域。
線程:就是在一個進程中負責一個執行路徑。
多線程:就是在一個進程中多個執行路徑同時執行。

1.1多線程的好處:

  1. 解決了一個進程里面可以同時運行多個任務(執行路徑)。
  2. 提供資源的利用率,而不是提供效率。

1.2多線程的弊端:

  1. 降低了一個進程里面的線程的執行頻率。
  2. 對線程進行管理要求額外的 CPU開銷。線程的使用會給系統帶來上下文切換的額外負擔。
  3. 公有變量的同時讀或寫。當多個線程需要對公有變量進行寫操作時,后一個線程往往會修改掉前一個線程存放的數據,發生線程安全問題。
  4. 線程的死鎖。即較長時間的等待或資源競爭以及死鎖等多線程癥狀。

二、創建線程

2.1 創建線程的方式一(繼承)

通過繼承Thread來創建線程。步驟:

  1. 自定義一個類繼承Thread.
  2. 重寫Threadrun方法。
  3. 創建Thread子類的對象,然后調用start方法開啟一個線程。

注意:千萬不要直接調用run方法,直接調用run方法就相當于調用了一個普通的方法而已,并沒有開啟一個新的線程。


public class Demo1 extends Thread {
    //自定義線程的任務代碼寫到run方法中。
    @Override
    public void run() {
        for(int i = 0 ; i<100 ; i++){
            System.out.println("自定義線程:"+ i);
        }
    }
    public static void main(String[] args) throws Exception {
        //主線程
        Demo1 d = new Demo1();
        d.start();//開啟了一個新的線程,一個線程開啟的時候就會執行run方法中的代碼
        for(int i = 0 ; i<100 ; i++){
            System.out.println("主線程:"+ i);
        }   
    }
}

2.2 為什么要重寫run()方法?

每個線程都有自己的任務代碼,主線程的任務代碼是在main方法中,因為每個線程都有自己要執行的代碼,自定義線程要執行的代碼就放在run方法 中。重寫run方法的目的就是把自定義線程的任務代碼編寫到run方法中。

2.3 線程的使用細節

  1. 線程的啟動使用父類的start()方法
  2. 如果線程對象直接調用run(),那么JVM不會把它當作線程來運行,會認為是普通的方法調用
  3. 線程的啟動只能有一次,否則拋出異常
  4. 可以直接創建Thread類的對象并啟動該線程,但是如果沒有重寫run(),什么也不執行
  5. 可以使用匿名內部類的實現方式來啟動一個線程

2.4 線程的多種狀態

線程狀態之間的轉換
線程狀態之間的轉換
  • 創建:新創建了一個線程對象。
  • 可運行:線程對象創建后,其線程調用了該對象的start()方法。該狀態的線程位于可運行線程池中,變得可運行,等待獲取cpu的執行權。
  • 運行:就緒狀態的線程獲取了CPU執行權,執行程序代碼。
  • 阻臨時塞: 阻塞狀態是線程因為某種原因放棄CPU使用權,例如調用了sleep或者wait方法,線程會暫時停止運行。直到線程進入就緒狀態,才有機會轉到運行狀態
  • 死亡:線程執行完它的任務時

2.5 線程的常用方法

  • ·Thread(String name) 初始化線程的名字
  • getName() 返回線程的名字
  • setName(String name) 設置線程對象名
  • sleep() 靜態的方法,線程睡眠指定的毫秒數。使用該方法需要拋出異常,并不會釋放鎖對象
  • getPriority() 返回當前線程對象的優先級,默認線程的優先級是5
  • setPriority(int newPriority) 設置線程的優先級,雖然設置了線程的優先級,但是具體的實現取決于底層的操作系統的實現(最大的優先級是10 ,最小的1 , 默認是5)
  • currentThread() 返回CPU正在執行的線程的對象
  • getId() 返回該線程的標識符。線程 ID 是一個正的 long型數值,在創建該線程時生成。線程ID是唯一的,并終生不變。線程終止時,該線程 ID 可以被重新使用。

2.6 創建線程的方式二(實現Runnable接口)

創建線程的第二種方式:實現Runnable接口。該類中的代碼就是對線程要執行的任務的定義。步驟如下:

  1. 定義一個實現Runnable接口的類
  2. 實現Runnable接口中的run方法,就是將線程運行的代碼放入在run方法中
  3. 通過Thread類建立線程對象
  4. Runnable接口的子類對象作為實際參數,傳遞給Thread類構造方法
  5. 調用Thread類的start方法開啟線程,線程最終會調用Runable接口子類的run方法
class RunableDemo1 {
    public static void main(String[] args) {
        //1.創建Runnable的子類對象
        MyRun mr = new MyRun();
        //2.通過Runnbale的子類對象創建線程對象
        Thread t1 = new Thread(mr);
        //3.啟動線程
        t1.start();
        for (int i = 0; i < 200; i++) {
            System.out.println("main:"+i);
        }

    }
}

class MyRun implements Runnable{    //建立Runnable接口的實現類
    @Override
    public void run() {
        for(int i=0;i<200;i++){
            System.out.println("MyRun"+i);
        }
    }   
}  

【提示】推薦使用第二種方式,即實現Runnable接口的方式。因為java是單繼承的。

2.7 為什么要將Runnable接口的子類對象傳遞給Thread的構造函數?

因為自定義的run方法所屬對象是Runnable接口的子類對象,所以要讓線程去執行指定對象的run方法。在創建Thread線程對象的時候,會調用線程的run方法,而調用線程run方法的時候又會去調用Runnable接口的實現類對象的run方法,來執行線程代碼。Thread類的構造方法,可以接收一個Runnable接口的子類對象。

2.8 關于Runnable的實現類對象

Runnable實現類的對象并不是線程對象,因為它沒有start方法。只有Thread類對象極其子類對象才是一個線程對象。


近期關于java基礎的同系列文章:
JavaSE基礎知識筆記
Java基礎:面向對象(1)--對象的概念、成員變量與局部變量、匿名對象、類的封裝

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 本文主要講了java中多線程的使用方法、線程同步、線程數據傳遞、線程狀態及相應的一些線程函數用法、概述等。 首先講...
    李欣陽閱讀 2,482評論 1 15
  • 寫在前面的話: 這篇博客是我從這里“轉載”的,為什么轉載兩個字加“”呢?因為這絕不是簡單的復制粘貼,我花了五六個小...
    SmartSean閱讀 4,776評論 12 45
  • Java多線程學習 [-] 一擴展javalangThread類 二實現javalangRunnable接口 三T...
    影馳閱讀 2,981評論 1 18
  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法,內部類的語法,繼承相關的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,740評論 18 399
  • 戀愛中你遇到過一兩個渣男,正常!因為老天總要讓你受點教訓,這是成長的必經之路。 如果你總是被騙,而且還是被同一個男...
    鯊魚小姐閱讀 2,040評論 2 5