併發編程之線程第一篇

来源:https://www.cnblogs.com/haizai/archive/2020/02/07/12274414.html
-Advertisement-
Play Games

併發編程之線程第一篇 3.4 原理之線程運行 線程上下文切換(Thread Context Switch) 3.5 常見方法 3.6 start與run 3.7 sleep與yield 案例 - 防止CPU占用100% 3.8 join方法詳解 3.9 interrupt方法詳解 兩階段終止模式 3 ...


併發編程之線程第一篇

 

3.4 原理之線程運行

Java虛擬機棧
JVM中由堆、棧、方法區所組成,其中棧記憶體是給線程使用,每個線程啟動後,虛擬機就會為其分配一塊棧記憶體。

  • 每個棧由多個棧幀(Frame)組成,對應著每次方法調用時所占用的記憶體
  • 每個線程只能有一個活動棧幀,對應著當前正在執行的那個方法

線程上下文切換(Thread Context Switch)

因為以下一些原因導致cpu不再執行當前的線程,轉而執行另一個線程的代碼

  • 線程的cpu時間片用完
  • 垃圾回收
  • 有更高優先順序的線程需要運行
  • 線程自己調用了sleep、yield、join、park、synchronized、lock等方法程式
    當Context Switch發生時,需要由操作系統保存當前線程的狀態,並恢復另一個線程的狀態,Java中對應的概念就是程式計數器(Program Counter Register),它的作用是記住下一條jvm指令的執行地址,是線程私有的
    在這裡插入圖片描述

3.5 常見方法

方法名功能說明註意
start() 啟動一個新線程,在新的線程運行run方法中的代碼 start方法只是讓線程進入就緒,裡面的代碼不一定立刻運行(CPU的時間片還沒分給它)。每個線程對象的start方法只能調用一次,如果調用了多次會出現IllegalThreadStateException
run() 新線程啟動後會調用的方法 如果在構造Thread對象時傳遞了Runnable參數,則線程啟動後調用Runnable中的run 方法,否則預設不執行任何操作。但可以創建Thread的子類對象,來覆蓋預設行為
join() 等待線程運行結束  
join(long n) 等待線程運行結束,最多等待n毫秒  
getId() 獲取線程長整型的id id唯一
getName() 獲取線程名  
setName(String) 修改線程名  
getPriority() 獲取線程優先順序  
setPriority(int) 修改線程優先順序 java中規定線程優先順序是1~10的整數,較大的優先順序能提高該線程被CPU調度的機率
getState() 獲取線程狀態 java中線程狀態是用6個enum表示,分別為 :NEW,RUNNABLE,BLOCKED,WAITING,TIMED_WAITING,TERMINATED
isInterrupted() 判定是否被打斷 不會清除打斷標記
isAlive() 線程是否存活(還沒有運行完畢)  
interrupt() 打斷線程 如果被打斷線程正在sleep,wait,join會導致被打斷的線程拋出InterruptedException,並清除打斷標記;如果打斷的正在運行的線程,則會設置打斷標記;park的線程被打斷,也會設置打斷標記
interrupted() static 判定當前線程是否被打斷 會清除打斷標記
currendThread(0 static 獲取當前正在執行的線程  
sleep(long n) static 讓當前執行的線程休眠n毫秒,休眠時讓出cpu的時間片給其他線程  
yieId() static 提示線程調度器讓出當前線程對CPU的使用 主要是為了測試和調試

3.6 start與run

調用run
在這裡插入圖片描述
輸出
在這裡插入圖片描述
程式仍在main線程運行,FileReader.read()方法調用還是同步的

3.7 sleep與yield

sleep

  1. 調用sleep會讓當前線程從Running進入Timed Waiting狀態
  2. 其它線程可以使用 interrupt方法打斷正在睡眠的線程,這時sleep方法會拋出InterruptedException
  3. 睡眠結束後的線程未必會立刻得到執行
  4. 建議用TimeUnit的sleep代替Thread的sleep來獲得更好地可讀性
    yield
    1、 調用yield會讓當前線程從Running進入Runnable狀態,然後調度執行其它同優先順序的線程。如果這時沒有同優先順序的線程,那麼不能保證讓當前線程暫停的效果
    2、具體的實現依賴於操作系統的任務調度器
    線程優先順序
  • 線程優先順序會提示(hint)調度器優先調度該線程,但它僅僅是一個提示,調度器可以忽略它
  • 如果cpu比較忙,那麼優先順序高的線程會獲得更多的時間片,但cpu閑時,優先順序幾乎沒作用
    在這裡插入圖片描述

案例 - 防止CPU占用100%

sleep實現
在沒有利用cpu來計算時,不要讓while(true)空轉浪費cpu,這時可以使用yield或sleep來讓出cpu的使用權給其他程式
在這裡插入圖片描述

  • 可以用wait或條件變數達到類似的效果
  • 不同的是,後兩種都需要加鎖,並且需要相應的喚醒操作,一般適用於要進行同步的場景
  • sleep適用於無需鎖同步的場景

3.8 join方法詳解

為什麼需要join
下麵的代碼執行,列印r是什麼?
在這裡插入圖片描述
分析

  • 因為主線程和線程t1是並行執行的,t1線程需要1秒之後才能算出r=10
  • 而主線程一開始就要列印r的結果,所以只能列印出r=0
    解決方法
  • 用sleep行不行?為什麼?
  • 用join,加在start之後即可
    在這裡插入圖片描述
    應用之同步 (案例1)
    以調用方角度來講,如果
  • 需要等待結果返回,才能繼續運行就是同步
  • 不需要等待結果返回,就能繼續運行就是非同步
    在這裡插入圖片描述
    在這裡插入圖片描述
    在這裡插入圖片描述
    在這裡插入圖片描述
    有時效的join
    等夠時間
    在這裡插入圖片描述
    輸出
    在這裡插入圖片描述

3.9 interrupt方法詳解

打斷sleep,wait,join的線程
打斷sleep的線程,會清空打斷狀態,以sleep為例
在這裡插入圖片描述
輸出
在這裡插入圖片描述
打斷正常運行的線程
打斷正常運行的線程,不會清空打斷狀態
在這裡插入圖片描述
輸出
在這裡插入圖片描述

兩階段終止模式

Two Phase Termination
在一個線程T1中如何“優雅”終止線程T2?這裡的【優雅】指的是給T2一個料理後事的機會。
1、 錯誤思路

  • 使用線程對象的stop()停止線程
    (1)stop方法會真正殺死線程,如果這時線程鎖住了共用資源,那麼當它被殺死後就再也沒有機會釋放鎖,其它線程將永遠無法獲取鎖。
  • 使用System.exit(int)方法停止線程
    (1)目的僅是停止一個線程,但這種做法會讓整個程式都停止
    在這裡插入圖片描述
package com.example.demo;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class TwoPhaseTermination {
    public static void main(String[] args) throws InterruptedException {
        Test test = new Test();
        test.start();

        Thread.sleep(3500);
        test.stop();
    }
}

@Slf4j
class Test{
    private Thread monitor;

    /**
     * 啟動監控線程
     */
    public void start() {
        monitor = new Thread(() -> {
            while (true) {
                Thread currentThread = Thread.currentThread();
                if (currentThread.isInterrupted()) {
                    log.info("料理後事");
                    break;
                }
                try {
                    // 情況1
                    Thread.sleep(1000);
                    log.info("執行監控記錄");
                } catch (Exception e) {
                	// 因為sleep出現異常後,會消除打斷標記
                    // 需要重置打斷標記
                    e.printStackTrace();
                    currentThread.interrupt();
                }
            }
        });
        monitor.start();
    }

    /**
     * 停止監控線程
     */
    public void stop() {
        monitor.interrupt();
    }

}

在這裡插入圖片描述
打斷park線程
打斷park線程,不會清空打斷狀態
在這裡插入圖片描述
輸出
在這裡插入圖片描述
如果打斷標記已經是true,則park會失效,可以如下操作 :
在這裡插入圖片描述

3.10 不推薦的方法

還有一些不推薦使用的方法,這些方法已過時,容易破壞同步代碼塊,造成線程死鎖。

方法名static功能說明
stop()   停止線程運行
suspend()   掛起(暫停)線程運行
resume()   恢複線程運行

3.11 主線程與守護線程

預設情況下,Java進程需要等待所有線程都運行結束,才會結束。有一種特殊的線程叫做守護線程,只要其它非守護線程運行結束了,即使守護線程的代碼沒有執行完,也會強制結束。
在這裡插入圖片描述
在這裡插入圖片描述
註意

  • 垃圾回收器線程就是一種守護線程
  • Tomcat中的Acceptor和Poller線程都是守護線程,所以Tomcat接收到shutdown命令後,不會等待它們處理完當前請求。

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

-Advertisement-
Play Games
更多相關文章
  • Tensorflow機器學習入門——網路可視化TensorBoard ...
  • *Preparation 1. Black's Futures Option Model (1) Key parameter: S = F, b = 0; (2) Task: Need an option for an asset (futures price = 120), assume K = ...
  • 一、前言 近期疫情嚴重,身為社畜的我只能在家中繼續鑽研技術了。之前寫過一篇關於搭建FIFO驗證平臺的博文,利用SV的OOP特性對FIFO進行初步驗證,但有很多不足之處,比如結構不夠規範、驗證組件類不獨立於DUT等問題。此次嘗試驗證更複雜的IP,並利用SV的更多高級特性來搭建層次化驗證平臺。 二、AP ...
  • JavaSE學習筆記(5) 內部類和String類 一.內部類基礎 轉自 "菜鳥教程" ​ 在 Java 中,可以將一個類定義在另一個類裡面或者一個方法裡面,這樣的類稱為內部類。廣泛意義上的內部類一般來說包括這四種:成員內部類、局部內部類、匿名內部類和靜態內部類。下麵就先來瞭解一下這四種內部類的用法 ...
  • Tensorflow機器學習入門,捲積神經網路識別MINIST手寫體數據集 ...
  • JavaSE學習筆記(4) 抽象類和介面 抽象方法和抽象類 ·抽象方法 使用abstract修飾的方法,沒有方法體,只有聲明。定義的是一種“規範”,就是告訴子類必須要給抽象方法提供具體的實現。 特點 1. 抽象方法必須聲明在抽象類中。 2. 抽象方法聲明引入了一個新方法,但不提供該方法的實現,由於抽 ...
  • Lamda表達式學習筆記二 lamda表達式 方法引用 上一篇講到Lamda體就是對函數式介面方法的實現 ,在方法體中我們可能會引用其他方法實現邏輯,所以在lamda體中我們可以直接引用器方法 I 對象::實例方法名 /** * 對象::實例方法名 */ @Test public void test ...
  • 註意:可變參數類型是在jdk1.5版本的新特性,數組類型是jdk1.0就有了。 這篇文章主要介紹了Java方法的可變參數類型,通過實例對Java中的可變參數類型進行了較為深入的分析,需要的朋友可以參考下。 Java方法中的可變參數類型是一個非常重要的概念,有著非常廣泛的應用。本文就以實例形式對此加以 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...