為什麼啟動線程是start方法?

来源:https://www.cnblogs.com/taojietaoge/archive/2020/06/18/13154638.html
-Advertisement-
Play Games

為什麼啟動線程是start方法 十年可見春去秋來,百年可證生老病死,千年可嘆王朝更替,萬年可見鬥轉星移。 凡人如果用一天的視野,去窺探百萬年的天地,是否就如同井底之蛙? 背景:啟動線程是start() 還是run() 方法?相信這個問題很多人都知道是start(),但是如果我再問下去呢,為什麼是st ...


為什麼啟動線程是start方法

 

十年可見春去秋來,百年可證生老病死,千年可嘆王朝更替,萬年可見鬥轉星移。

             凡人如果用一天的視野,去窺探百萬年的天地,是否就如同井底之蛙?

 

背景:啟動線程是start() 還是run() 方法?相信這個問題很多人都知道是start(),但是如果我再問下去呢,為什麼是start()?你會如何作答呢?

 

一、理論課

當用start()開始一個線程後,線程就進入就緒狀態,使線程所代表的虛擬處理機處於可運行狀態,這意味著它可以由JVM調度並執行;但是這並不意味著線程就會立即運行,只有當cpu分配時間片時,這個線程獲得時間片時,才開始執行run()方法;start()方法去調用run(),而run()方法則是需要去重寫的,其包含的是線程的主體(真正的邏輯)。

二、線程六大狀態

Java 中,定義了 6 種線程狀態,NEWRUNNABLEBLOCKEDWAITINGTIMED_WAITING和TERMINATED

1 public enum State{
2    NEW,  
3    RUNNABLE,
4    BLOCKED,
5    WAITING,
6    TIMED_WAITING,
7    TERMINATED;     
8 }

6 種線程狀態關係圖

 

三、代碼層次

楊總說的,一切問題歸咎於源碼!

start 方法的源碼:

public synchronized void start() {
        /**
         * This method is not invoked for the main method thread or "system"
         * group threads created/set up by the VM. Any new functionality added
         * to this method in the future may have to also be added to the VM.
         *
         * A zero status value corresponds to state "NEW".
         */
         // 未初始化則拋異常   
        if (threadStatus != 0)
            throw new IllegalThreadStateException();

        /* Notify the group that this thread is about to be started
         * so that it can be added to the group's list of threads
         * and the group's unstarted count can be decremented. */
        group.add(this);

        // 是否啟動標誌符
        boolean started = false;
        try {
            /**
             * start0() 是啟動多線程的關鍵
             * 執行完成之後,新的線程已經在運行了
             * 這裡會創建一個新的線程,是一個 native 方法
             */
            start0();
            // 主線程執行
            started = true;
        } finally {
            try {
                if (!started) {
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
                /* do nothing. If start0 threw a Throwable then
                  it will be passed up the call stack */
            }
        }
    }

 run方法源碼:

 @Override
    public void run() {
     // 簡單的運行,不會新起線程,target 是 Runnable
        if (target != null) {
            target.run();
        }
    }

從start()和run()方法的源碼可以看出,start方法的源碼也沒幾行代碼,最主要的是 start0() 方法;run() 方法的源碼也比較簡單的,就是一個普通方法的調用;重點是這個 start0() 方法,她是真正實現多線程的關鍵。

start0方法源碼:

// native :就是本地方法 
private native void start0(); 

關於native方法簡述:

1、被native關鍵字修飾的方法叫做本地方法,本地方法和其它方法不一樣,本地方法意味著和平臺有關,因此使用了native的程式可移植性都不太高;

2、native方法在JVM中運行時數據區也和其它方法不一樣,它有專門的本地方法棧;

3、native方法主要用於載入文件和動態鏈接庫,由於Java語言無法訪問操作系統底層信息(比如:底層硬體設備等),這時候就需要藉助C語言來完成了;

4、被native修飾的方法可以被C語言重寫。

Java 跨平臺圖

 

在start()中start0 被標記成 native ,也就是本地方法,並不需要我們去實現或者瞭解,只要瞭解下為什麼 start0() 會標記成 native ?

如上圖,start() 方法調用 start0() 方法後,該線程並不一定會立馬執行,只是將線程變成了可運行狀態(NEW ---> RUNNABLE);具體什麼時候執行,取決於 CPU ,由 CPU 統一調度;我們又知道 Java 是跨平臺的,可以在不同系統上運行,每個系統的 CPU 調度演算法不一樣,所以就需要做不同的處理,這件事情就只能交給 JVM 來實現了,start0() 方法自然就表標記成了 native。

 四、總結

Java 中實現真正的多線程是 start 中的 start0() 方法,run() 方法只是一個包含業務邏輯普通的方法;start是啟動多線程的唯一方式,其使得線程由創建態到就緒態,而這個線程是否被運行是由系統調度所決定的。

 

  十年可見春去秋來

    百年可證生老病死

      千年可嘆王朝更替

        萬年可見鬥轉星移

          凡人如果用一天的視野

               去窺探百萬年的天地

                  是否就如同井底之蛙?

 

 

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 訪問者模式是一種較為複雜的行為型設計模式,它包含訪問者和被訪問元素兩個主要組成部分,這些被訪問的元素具有不同的類型,且不同的訪問者可以對其進行不同的訪問操作 模式動機 對於系統中某些對象,它們存儲在同一個集合中,且具有不同的類型。對於該集合中的對象,可以接受一類稱為訪問者的對象來訪問,不同的訪問者其 ...
  • 1.模型管理 :web線上流程設計器、預覽流程xml、導出xml、部署流程 2.流程管理 :導入導出流程資源文件、查看流程圖、根據流程實例反射出流程模型、激活掛起 3.運行中流程:查看流程信息、當前任務節點、當前流程圖、作廢暫停流程、指派待辦人 4.歷史的流程:查看流程信息、流程用時、流程狀態、查看 ...
  • #一、解釋器模式介紹 ##1、定義與類型 定義:給定一個語言,定義它的文法的一種表示,並定義一個解釋器,這個解釋器使用該表示來解釋語言中的句子。 為瞭解釋一種語言,而為語言創建的解釋器 類型:行為型 #2、適用場景 某個特定類型問題發生頻率足夠高 ##3、優點 語法由很多類表示,容易改變及擴展此“語 ...
  • 首先是個人的一些閱讀源碼的小技巧,不一定適用每個人,可以直接跳過。 閱讀源碼的一些個人技巧 博客+總結 個人覺得大多數情況下跟著一篇優秀的博客配合著看就足夠了,之後再自己寫博客總結一遍加深印象,畫一下流程圖基本都能理順。(圖為學AQS時本人畫的獲取獨占鎖流程圖) 類關係 配合idea看類之間的關係( ...
  • 一、網格包佈局舉例 1.這裡構造一個3*3的佈局。 package com.bjpowernode.java_learning; ​ import java.awt.Frame; import java.awt.*; ​ public class D123_1_GridLayout { public ...
  • 1. Redis簡介 Redis(Remote Dictionary Server ),即遠程字典服務,是一個開源的使用ANSI C語言編寫、支持網路、可基於記憶體亦可持久化的日誌型、Key-Value 資料庫,並提供多種語言的API。Redis 是一個高性能的key-value資料庫。 redis的 ...
  • 博客園添加live2d看板娘 博客說明 文章所涉及的資料來自互聯網整理和個人總結,意在於個人學習和經驗彙總,如有什麼地方侵權,請聯繫本人刪除,謝謝! 配置 添加代碼到博客園側邊欄公告 代碼 <script src="https://eqcn.ajz.miesnfu.com/wp-content/pl ...
  • 什麼是列表? 列表是由一系列按照特定順序排列的元素組成,直觀理解就是:數組。 只不過python的列表有點特別,他不限制存儲的元素類型,使用手感上來說反倒更像是對標Java中的ArrayList。 flowers = ['Rose','Lily','Jasmine','Rosemary'] prin ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...