【安卓筆記】進程和線程的基礎知識

0. 環境:

電腦:Windows10

Android Studio: 2024.3.2

編程語言: Java

Gradle version:8.11.1

Compile Sdk Version:35

Java 版本:Java11

1. 先熟悉JVM虛擬機的線程

----------以下都是系統線程,由JVM管理,通常無需直接操作,僅需了解即可。----------

先創建一個Java module(創建方法可以看我這篇文章的3.1)

3.1 創建module

首先,創建一個module:菜單--file--new--new module...

?

注意左側選擇Java or Kotlin Library,右側填寫相應信息。點finish

?

?然后執行以下代碼:

public static void main(String[] args) {// 虛擬機線程管理的接口ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();// 取得線程信息ThreadInfo[] threadInfos = threadMXBean.dumpAllThreads(false, false);for (ThreadInfo threadInfo : threadInfos) {String logInfo = String.format("[%s] + %s", threadInfo.getThreadId(), threadInfo.getThreadName());// 打印線程Id和線程名稱System.out.println(logInfo);}
}

運行后看結果:

[1] + main
[9] + Reference Handler
[10] + Finalizer
[11] + Signal Dispatcher
[12] + Attach Listener
[19] + Notification Thread
[20] + Common-Cleaner
---線程名稱------作用---
main主線程,程序入口
Reference Handler處理引用對象
Finalizer執行對象的finalize()方法
Signal Dispatcher處理操作系統信號
Attach Listener支持動態附加(Attach)到JVM
Notification Thread處理JMX(Java管理擴展)通知
Common-Cleaner替代Finalizer的輕量級清理線程(Java 9+引入)

(沒有看到GC線程,是因為目前沒有資源需要回收。當出現資源需要回收時,才會觸發JVM的GC線程。此時才有GC線程來回收資源。也就是GC回收機制)

----------以上都是系統線程,由JVM管理,通常無需直接操作,僅需了解即可。----------

?2. 運行線程的方式

三種方式:

--名稱--備注
Thread線程
Runable任務,需要通過thread來運行該任務
Callable有返回值的任務,需要通過futureTask來掛載

示例代碼:

// 第一種方式:thread
private static class Thread1 extends Thread {@Overridepublic void run() {super.run();System.out.println("--- run thread1 ---");}
}
// 第二種方式:runnable
private static class Runnable2 implements Runnable {@Overridepublic void run() {System.out.println("--- run runnable2 ---");}
}
// 第三種方式:callable
private static class Callable3 implements Callable<String> {@Overridepublic String call() throws Exception {System.out.println("--- run callable3 ---");return "[result]: run success";}
}

運行方式如下:

public static void main(String[] args) {// 方法一的線程可以通過start()方法直接運行Thread1 thread1 = new Thread1();thread1.start(); // 需要通過start()來啟動線程。run()函數不是啟動線程,只是函數調用// 方法二的任務,需要通過線程來執行Runnable2 runnable2 = new Runnable2();Thread thread = new Thread(runnable2);thread.start();// 方法三的有返回值的任務,需要掛載在FutureTask,再通過線程來執行Callable3 callable3 = new Callable3();// 將callable掛載在futureTask上FutureTask<String> futureTask = new FutureTask<>(callable3);// 通過線程來執行futureTask任務Thread callableThread = new Thread(futureTask);callableThread.start();// 此時我們可以獲取callable的返回值try {System.out.println("callable return: " + futureTask.get());} catch (InterruptedException e) {throw new RuntimeException(e);} catch (ExecutionException e) {throw new RuntimeException(e);}
}

運行后,可以看到結果:

--- run thread1 ---
--- run runnable2 ---
--- run callable3 ---
callable return: [result]: run success

3. 停止線程的方式

1. stop()停止(不推薦!)

非常不推薦使用stop()來停止線程,過時了。該函數屬于暴力停止,有一定的危險性。例如來不及釋放、會產生碎片等問題。甚至會被其他程序員鄙視(開玩笑的)

你就想吧,你在KTV里唱歌,唱到一半被人切歌了。你是不是想給他一拳

2. interrupt()中斷

優雅的停止線程的方式,應該是讓run()函數執行完之后,不再執行。

interrupt()是中斷信號的函數

private static class InterruptThread extends Thread {@Overridepublic void run() {super.run();String threadInfo = String.format("[%s] %s", Thread.currentThread().getId(), Thread.currentThread().getName());String isRunning = String.format("%s is Running", threadInfo);String isStopped = String.format("%s is Stopped", threadInfo);while (!isInterrupted()) { // 注意這里,需要增加 中斷信號的判斷System.out.println(isRunning);}System.out.println(isStopped);// -------------以下為錯誤示范---------------/**while (true) { // 如果判斷條件為true時,即使調用了thread.interrupt(). 該線程也無法停止System.out.println(isRunning);}System.out.println(isStopped);*/}
}

執行代碼方法如下:

InterruptThread thread = new InterruptThread();
thread.start(); // 開啟線程
try {Thread.sleep(10);
} catch (InterruptedException e) {throw new RuntimeException(e);
}
thread.interrupt(); // 發起中斷信號

運行后,可以看到結果:

[21] Thread-0 is Running
[21] Thread-0 is Running
·····
[21] Thread-0 is Running
[21] Thread-0 is Running
[21] Thread-0 is Stopped

?最后確實停止了。

中斷后,沒有重啟的概念。只有線程啟動、線程中斷(也就是停止)。要想再次啟動線程,需要再次使用線程啟動。

注意:

如果在run()函數中使用了sleep(),會導致interrupt信號被清除。如果需要使用sleep()函數,需要在拋異常部分,再次發送一次interrupt(); 這樣即可中斷線程。

參考示例:

private static class Thread1 extends Thread {@Overridepublic void run() {super.run();try {System.out.println("--- run thread1 ---");Thread.sleep(1000);} catch (InterruptedException e) {interrupt(); // 再次發送中斷信號e.printStackTrace();}}
}

擴展:

如果不是繼承Thread,而是實現Runnable,需要怎么改呢?

請看代碼:

private static class InterruptThread2 implements Runnable {@Overridepublic void run() {String threadInfo = String.format("[%s] %s", Thread.currentThread().getId(), Thread.currentThread().getName());String isRunning = String.format("%s is Running", threadInfo);String isStopped = String.format("%s is Stopped", threadInfo);// 通過Thread.currentThread(),來獲取線程while (!Thread.currentThread().isInterrupted()) {System.out.println(isRunning);}System.out.println(isStopped);}
}

4. 補充一個join()函數

join()的意思是放棄當前線程的執行,并返回對應的線程。

如果不是用join()會導致線程之間隨機執行,無法做到控制順序。

應用場景:執行完線程1后,需要執行線程2,則可以對線程1執行join()函數,再對線程2執行start()函數。達到先執行線程1,再執行線程2,從而達到控制線程執行順序的效果。

貼代碼

private static class InterruptThread extends Thread {public InterruptThread(String s) {super(s);//傳入線程名稱,用于區分不同線程}@Overridepublic void run() {super.run();String threadInfo = String.format("[%s] %s", Thread.currentThread().getId(), Thread.currentThread().getName());for (int i = 0; i < 100; i++) {System.out.println(i + ";" + getName() + threadInfo);}}
}
//執行代碼:
InterruptThread thread1 = new InterruptThread("A");
InterruptThread thread2 = new InterruptThread("B");
thread1.start();
// thread1.join();//注意這個join。可以做到先執行thread1
thread2.start();

執行后看結果:

0;B[22] B
1;B[22] B
2;B[22] B
3;B[22] B
4;B[22] B
5;B[22] B
6;B[22] B
0;A[21] A
7;B[22] B
1;A[21] A
8;B[22] B
9;B[22] B
10;B[22] B
11;B[22] B
12;B[22] B
13;B[22] B
14;B[22] B
15;B[22] B
2;A[21] A
16;B[22] B
3;A[21] A
17;B[22] B
4;A[21] A
18;B[22] B
···

可以看到線程A和線程B混在一起,無法做到先后執行。如果使用了thread1.join(); 再運行之后,就可以做到執行完線程A后,再開始執行線程B。?

運行結果:

0;A[21] A
1;A[21] A
2;A[21] A
3;A[21] A
4;A[21] A
···
97;A[21] A
98;A[21] A
99;A[21] A
// 可以看到,完全執行完線程A之后,才會執行線程B
0;B[22] B
1;B[22] B
2;B[22] B
3;B[22] B
4;B[22] B
···
97;B[22] B
98;B[22] B
99;B[22] B

?5. sleep()和wait()的區別

sleepwait
是休眠是等待
可以無條件休眠

特殊原因需要等待

(例如:資源不足)

休眠需要帶參: 休眠時間調用不用帶參
休眠結束后,立刻有執行權需要手動喚醒,才有執行權
sleepwait
是休眠是等待
可以無條件休眠

特殊原因需要等待

(例如:資源不足)

休眠需要帶參: 休眠時間調用不用帶參
休眠結束后,立刻有執行權需要手動喚醒,才有執行權
會清除interrupt信號

?執行權并不代表馬上執行。什么時候執行 取決于操作系統的調度。

寫在最后

至此,我們就學會了線程的啟動和停止。順便學會了順序執行線程。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/91076.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/91076.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/91076.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

26-計組-多處理器

多處理器的基本概念1. 計算機體系結構分類依據&#xff1a;根據指令流和數據流的數量關系&#xff0c;計算機體系結構可分為四種類型&#xff1a;SISD、SIMD、MISD、MIMD。&#xff08;1&#xff09;SISD 單指令流單數據流定義&#xff1a;任意時刻計算機只能執行單一指令操作單…

vscode 插件開發activityba

在 VS Code 插件開發中&#xff0c;**Activity Bar&#xff08;活動欄&#xff09;**是左側垂直導航欄的核心組成部分&#xff0c;它為用戶提供了快速訪問插件功能的入口。通過自定義 Activity Bar&#xff0c;開發者可以顯著提升插件的可見性和用戶體驗。以下是關于 Activity …

【橘子分布式】Thrift RPC(理論篇)

一、簡介 首先還是那句話&#xff0c;概念網上已經很多了&#xff0c;我們就不多逼逼了。我來大致介紹一下。 Thrift是一個RPC框架可以進行異構系統(服務的提供者 和 服務的調用者 不同編程語言開發系統)的RPC調用為什么在當前的系統開發中&#xff0c;會存在著異構系統的RPC…

項目進度依賴紙面計劃,如何提升計劃動態調整能力

項目進度依賴紙面計劃會導致實際執行中的調整能力不足。提升計劃動態調整能力的方法包括&#xff1a;建立動態進度管理系統、強化團隊溝通與協作、定期開展風險評估與進度復盤。特別是建立動態進度管理系統&#xff0c;通過信息技術工具實現實時跟蹤和反饋&#xff0c;使計劃能…

遞推預處理floor(log_2{n})

在C中&#xff0c;除了使用<cmath>中的log或log2函數求對數&#xff0c;也可以通過遞推求出所有可能用到的?log?2i?,i∈[1,n]\lfloor \log_2i\rfloor, i\in[1, n]?log2?i?,i∈[1,n] 證明&#xff1a;?log?2i??log?2?i2??1\lfloor \log_2i \rfloor\lfloor \…

【AI智能體】智能音視頻-搭建可視化智能體

可視化智能體是語音小伴侶智能體的升級版&#xff0c;支持語音與視頻的雙模態交互。本文詳細介紹了音視頻交互的實現原理、智能體搭建方法及效果測試&#xff0c;幫助開發者快速構建支持音視頻交互的智能體。 應用場景 可視化智能體適用于多種場景&#xff0c;舉例如下&#…

Sensoglove推出新一代外骨骼力反饋手套:主動力反饋+亞毫米級手指追蹤,助力機器人操控與虛擬仿真

在工業自動化、虛擬現實和醫療康復等領域&#xff0c;高精度手部交互設備的需求日益增長。Sensoglove推出的Rembrandt外骨骼力反饋手套&#xff0c;結合主動力反饋、觸覺反饋與亞毫米級追蹤技術&#xff0c;為用戶提供更自然、更安全的操作體驗。Sensoglove外骨骼力反饋手套核心…

AutoMapper入門

在 ASP.NET Core 開發中&#xff0c;我們經常需要在不同層之間傳遞數據&#xff1a;比如從數據庫模型&#xff08;Entity&#xff09;轉換到 DTO&#xff0c;再從 DTO 轉換為前端視圖模型。這些轉換代碼大量重復、冗長、容易出錯。為了解決這個問題&#xff0c;AutoMapper 誕生…

PyTorch武俠演義 第一卷:初入江湖 第1章:武林新秀遇Tensor - 張量基礎

第一卷&#xff1a;初入江湖 第1章&#xff1a;武林新秀遇Tensor - 張量基礎晨起碼農村 雞鳴三聲&#xff0c;林小碼已經收拾好了行囊。他最后看了眼床頭那本翻舊的《Python入門心法》&#xff0c;輕輕撫平卷起的書角。 "小碼&#xff0c;路上小心。"父親將一把青銅匕…

Python進階(4):類與面向對象程序設計

面向對象OOPOOP:Object Oriented Programming,面向對象編程,面向對象中的對象(Obiect)&#xff0c;通常是指客觀世界中存在的對象&#xff0c;這個對象具有唯一性&#xff0c;對象之間各不相同&#xff0c;各有各的特點&#xff0c;每個對象都有自己的運動規律和內部狀態;對象與…

如何在 Shopify 中創建退貨標簽

退貨是電商運營中不可避免的一環&#xff0c;而一個順暢、透明的退貨流程&#xff0c;不僅能減少客戶投訴&#xff0c;也有助于提升顧客對品牌的信任與忠誠度。Shopify 雖然沒有內建退貨標簽自動生成功能&#xff0c;但通過合理設置與外部工具整合&#xff0c;你完全可以打造一…

I2C設備寄存器讀取調試方法

1、查看I2C掛載設備 2、讀取i2C設備所有寄存器 3、讀取i2c設備的某個寄存器 4、向i2C設備某個寄存器寫入一個值1、查看

K8S的Helm包管理器

一、背景 官網: https://helm.sh/ 我們針對K8S環境中&#xff0c;部署對應的應用&#xff0c;無外乎就是編寫一堆yaml資源清單文件. 資源清單、依賴性少的時候&#xff0c;可以直接手動維護。但是&#xff0c;隨著資源清單越來越復雜&#xff0c;越來越多&#xff0c;不同的環…

多模態數據處理新趨勢:阿里云ODPS技術棧深度解析與未來展望

多模態數據處理新趨勢&#xff1a;阿里云ODPS技術棧深度解析與未來展望 &#x1f31f; 嗨&#xff0c;我是IRpickstars&#xff01; &#x1f30c; 總有一行代碼&#xff0c;能點亮萬千星辰。 &#x1f50d; 在技術的宇宙中&#xff0c;我愿做永不停歇的探索者。 ? 用代碼丈…

AI數據分析儀設計原理圖:RapidIO信號接入 平板AI數據分析儀

AI數據分析儀設計原理圖&#xff1a;RapidIO信號接入 平板AI數據分析儀 1 、概述 本儀器是一款面向工業控制、新能源、震動測量等業務開發的平板AI數據分析儀。基于 Jetson Orin Nano&#xff08;AI邊緣計算&#xff09;、實現RapidIO接口數據接入&#xff0c;進行AI分析。Rap…

人工智能正逐步商品化,而“理解力”才是開發者的真正超能力

每周跟蹤AI熱點新聞動向和震撼發展 想要探索生成式人工智能的前沿進展嗎&#xff1f;訂閱我們的簡報&#xff0c;深入解析最新的技術突破、實際應用案例和未來的趨勢。與全球數同行一同&#xff0c;從行業內部的深度分析和實用指南中受益。不要錯過這個機會&#xff0c;成為AI領…

玩轉ClaudeCode:ClaudeCode安裝教程(Windows+Linux+MacOS)

Windows 環境安裝 Claude Code 一、安裝 WSL 環境 1. 確認 Windows 功能已開啟 打開 “控制面板 → 程序 → 啟用或關閉 Windows 功能” 勾選 “適用于 Linux 的 Windows 子系統” 和 “虛擬機平臺” 點“確定”后重啟電腦。 開機后&#xff0c;管理員模式打開 Terminal…

PyTorch多層感知機(MLP)模型構建與MNIST分類訓練

沖沖沖&#x1f60a; here&#x1f60a; 文章目錄PyTorch多層感知機模型構建與MNIST分類訓練筆記&#x1f3af; 1. 任務概述?? 2. 環境設置2.1 導入必要庫2.2 GPU配置&#x1f9e0; 3. 模型構建3.1 模型定義關鍵點3.2 損失函數選擇3.3 模型初始化與設備選擇&#x1f527; 4. …

android tabLayout 切換fragment fragment生命周期

1、TabLayout 與 Fragment 結合使用的常見方式 通常會使用 FragmentPagerAdapter 或 FragmentStatePagerAdapter 與 ViewPager 配合,再將 TabLayout 與 ViewPager 關聯,實現通過 TabLayout 切換 Fragment。 以下是布局文件示例 activity_main.xml: <LinearLayout xmln…

馬蹄集 BD202401補給

可怕的戰爭發生了&#xff0c;小度作為后勤保障工作人員&#xff0c;也要為了保衛國家而努力。現在有 N(1≤N≤)個堡壘需要補給&#xff0c;然而總的預算 B(1≤B≤)是有限的。現在已知第 i 個堡壘需要價值 P(i) 的補給&#xff0c;并且需要 S(i) 的運費。 鑒于小度與供應商之間…