深度分析Android多線程編程

理解并正確運用多線程是構建高性能、流暢、響應迅速的 Android 應用的關鍵,但也充滿挑戰和陷阱。

核心挑戰:UI 線程(主線程)的限制

  • 唯一性: Android 應用只有一個主線程,負責處理所有用戶交互(觸摸事件、點擊等)、系統事件(生命周期回調)和 UI 更新(繪制視圖、修改視圖屬性)。
  • 性能瓶頸: 主線程必須保持高度響應。為了保證流暢的用戶體驗(通常目標是 60 FPS),主線程在每幀(約 16ms)內必須完成所有計算和繪制工作。
  • ANR (Application Not Responding): 如果主線程被阻塞超過一定時間(通常是 5 秒處理事件或 10 秒執行 BroadcastReceiver),系統會彈出 ANR 對話框,用戶體驗極差,甚至可能導致應用被殺死。
  • 規則: 嚴禁在主線程執行任何耗時操作(阻塞操作)! 這包括網絡請求、數據庫讀寫(尤其是大型或復雜查詢)、文件讀寫(特別是大文件)、復雜計算、圖像解碼/處理等。

解決方案:多線程編程模型

為了解決主線程瓶頸,必須將耗時操作轉移到后臺線程執行,完成后根據需要將結果安全地傳回主線程更新 UI。Android 提供了多種機制來實現這一點:

  1. 基礎:ThreadRunnable

    • 原理: Java 標準庫的核心。創建 Thread 對象并傳入一個 Runnable 任務,調用 start() 方法開始在新線程中執行 run() 方法。
    • 優點: 最基礎、最靈活。
    • 缺點:
      • 手動管理復雜: 需要顯式創建、啟動、管理線程(如停止、同步)。
      • 資源消耗: 無限制地創建新線程會導致大量開銷(內存、CPU 上下文切換),可能耗盡資源。
      • 難以復用: 線程創建銷毀成本高。
      • 同步困難: 需要開發者仔細處理線程間共享數據的同步(synchronized, volatile, Lock),極易出錯(死鎖、競態條件)。
      • 結果回傳: 需要配合 HandlerrunOnUiThread 才能安全更新 UI。
    • 適用場景: 簡單、短暫、不頻繁的后臺任務;學習理解線程基礎。實踐中不推薦直接大量使用裸 Thread
  2. Android 經典:Handler, LooperMessageQueue

    • 原理: Android 異步通信的核心機制。
      • Looper: 每個線程可以有且最多一個 Looper。它管理著一個 MessageQueue(消息隊列),不斷循環 (loop()) 地從隊列中取出 Message
      • MessageQueue: 存儲待處理的 Message 對象(包含數據、目標 Handler 等信息)。
      • Handler: 綁定到特定線程(通常是主線程)的 Looper 上。用于向該線程的 MessageQueue 發送 MessageRunnable。當 Looper 取出 Message 后,會分發給對應的 HandlerhandleMessage() 方法執行。
    • 優點:
      • 安全線程切換: 是實現將后臺線程結果安全傳回主線程更新 UI 的經典方式 (new Handler(Looper.getMainLooper())).
      • 消息驅動: 解耦了任務的提交和執行。
      • 延時/定時: 支持發送延時消息 (postDelayed, sendMessageDelayed)。
    • 缺點:
      • 代碼繁瑣: 需要定義 Message、創建 Handler、重寫 handleMessage,代碼結構可能變得冗長。
      • 內存泄漏風險: 非靜態內部類 Handler 會隱式持有外部類(通常是 Activity/Fragment)的引用。如果 Handler 的消息隊列中還有未處理的消息(例如延時消息),而外部類已被銷毀,就會導致內存泄漏(外部類無法被 GC)。必須使用靜態內部類 + WeakReferenceViewModel 來避免。
      • 回調嵌套: 復雜異步鏈容易導致“回調地獄”。
    • 適用場景: 需要精確控制消息調度(延時、定時)、與其他線程通信的基礎設施構建。更新 UI 仍是核心用途之一。
  3. 線程池:Executor 框架 (ThreadPoolExecutor, Executors)

    • 原理: Java java.util.concurrent 包提供。核心思想是預先創建一組線程(線程池),將提交的任務 (RunnableCallable) 放入任務隊列中,由池中的空閑線程執行。避免了頻繁創建銷毀線程的開銷。
    • 核心組件:
      • Executor: 執行任務的接口。
      • ExecutorService: 擴展 Executor,提供生命周期管理、異步任務提交(返回 Future)、批量任務提交等功能。
      • ThreadPoolExecutor: 可配置的線程池實現類。關鍵參數:
        • corePoolSize: 核心線程數(即使空閑也保留)。
        • maximumPoolSize: 最大線程數。
        • keepAliveTime: 非核心線程空閑超時時間。
        • workQueue: 任務隊列(如 LinkedBlockingQueue, SynchronousQueue)。
        • threadFactory: 創建新線程的工廠。
        • RejectedExecutionHandler: 當任務無法被接受(隊列滿且線程數達上限)時的處理策略(拋出異常、丟棄、丟棄最老任務、在調用者線程執行)。
      • Executors: 工廠類,提供創建常見配置線程池的便捷方法(但需注意其潛在問題):
        • newCachedThreadPool(): 無界線程池(Integer.MAX_VALUE 線程數),使用 SynchronousQueue。適用于大量短生命周期的異步任務。風險:可能創建大量線程導致 OOM。
        • newFixedThreadPool(int nThreads): 固定大小的線程池,使用無界 LinkedBlockingQueue。適用于控制并發數。風險:隊列無界,任務持續堆積可能 OOM。
        • newSingleThreadExecutor(): 單線程的線程池,使用無界隊列。保證任務順序執行。風險:隊列無界 OOM。
        • newScheduledThreadPool(int corePoolSize): 支持定時/周期性任務的線程池。
    • 優點:
      • 資源復用: 顯著降低線程創建銷毀開銷。
      • 控制并發: 有效管理并發線程數量,防止資源耗盡。
      • 統一管理: 簡化線程生命周期管理。
      • 提高響應: 任務到來時通常有線程立即執行(或很快有線程可用)。
    • 缺點:
      • 配置復雜: 需要根據任務類型(CPU密集型、IO密集型)和系統資源合理配置參數(corePoolSize, maxPoolSize, workQueue)。
      • Executors 陷阱: 默認創建的無界隊列線程池有 OOM 風險。最佳實踐是使用 ThreadPoolExecutor 構造函數,根據需求顯式配置有界隊列和合適的拒絕策略。
      • 結果處理: 使用 Future 獲取結果或處理異常,仍需結合其他機制(如 Handler)更新 UI。
    • 適用場景: 絕大多數后臺耗時任務的推薦方式! 如網絡請求、數據庫操作、文件讀寫、圖片處理等。是 AsyncTask 和很多現代框架的基礎。
  4. Android 特有(已廢棄/慎用):AsyncTask

    • 原理: 早期 Android 提供的簡化異步任務的抽象類。內部使用線程池執行后臺任務,并通過 Handler 機制將進度和結果回調到主線程。
      • onPreExecute(): 主線程執行,任務開始前準備(如顯示進度條)。
      • doInBackground(Params...): 后臺線程執行,真正的耗時操作。可調用 publishProgress(Progress...)
      • onProgressUpdate(Progress...): 主線程執行,處理進度更新(如更新進度條)。
      • onPostExecute(Result): 主線程執行,處理最終結果(如更新 UI)。
    • 優點: 簡化了線程切換和 UI 更新流程,代碼結構相對清晰(針對簡單場景)。
    • 缺點/廢棄原因:
      • 內存泄漏: 非靜態內部類持有 Activity/Fragment 引用,若任務在后臺執行而 Activity 被銷毀,會導致泄漏。
      • 生命周期問題: Activity 銷毀后任務仍在后臺執行,onPostExecute 可能嘗試更新已銷毀的 UI,導致崩潰或不一致狀態。需要手動取消任務 (cancel(true)) 并在 onDestroy 中處理,增加了復雜性。
      • 配置變更問題: 屏幕旋轉等配置變更導致 Activity 重建時,AsyncTask 與舊的 Activity 關聯失效,新 Activity 無法獲取結果。
      • 結果丟失: 如果 AsyncTask 被取消或 Activity 被銷毀,結果可能丟失。
      • 并發行為變化: 不同 Android 版本內部線程池實現不一致(并行 vs 串行)。
    • 現狀: 官方已廢棄 (deprecated)強烈建議使用 Executor + Handler 或更現代的解決方案(如協程)。 如果仍在使用舊代碼,務必嚴格處理生命周期和內存泄漏。
  5. 現代首選:Kotlin 協程 (Coroutines)

    • 原理: Kotlin 語言提供的輕量級并發框架。核心概念是“掛起”(suspend),而非阻塞線程。 協程在概念上可以理解為“用戶態線程”或“輕量級線程”,由 Kotlin 運行時管理,其調度開銷遠小于操作系統線程。協程可以在某個線程上掛起,釋放該線程去執行其他任務,并在適當時候恢復執行(可能在相同或不同線程)。
    • 關鍵組件:
      • suspend 函數: 標記可以掛起的函數。只能在協程或其他 suspend 函數中調用。
      • 協程構建器:
        • launch: 啟動一個不返回結果的協程(用于“發射后不管”的異步任務)。
        • async: 啟動一個返回 Deferred(類似 Future)結果的協程,可通過 await() 獲取結果。
      • 協程作用域 (CoroutineScope): 定義了協程的生命周期。所有協程構建器都是作用域的擴展函數。關鍵作用域:
        • GlobalScope: 應用生命周期范圍。一般不推薦使用,容易導致泄漏或任務無法取消。
        • lifecycleScope (Activity, Fragment): 綁定到 Android 組件的生命周期。組件銷毀時自動取消作用域內所有協程。UI 相關操作的推薦作用域。
        • viewModelScope (ViewModel): 綁定到 ViewModel 的生命周期。ViewModel 清除時自動取消。后臺操作(如數據加載)的首選作用域。
      • 調度器 (Dispatcher): 決定協程在哪個或哪些線程上執行。
        • Dispatchers.Main: 主線程,用于更新 UI 和調用輕量級掛起函數。
        • Dispatchers.IO: 適用于磁盤或網絡 I/O 操作的線程池。
        • Dispatchers.Default: 適用于 CPU 密集型計算(排序、解析等)的線程池。
        • Dispatchers.Unconfined: 不限定特定線程(不常用)。
      • 結構化并發: 協程通過作用域建立父子關系。父協程取消會自動取消所有子協程。子協程異常會傳播給父協程(除非用 SupervisorJob)。這極大地簡化了并發任務的生命周期管理和資源清理。
    • 優點:
      • 簡化異步代碼: 使用順序的、看似同步的代碼編寫異步邏輯,消除“回調地獄”,顯著提升可讀性和可維護性。
      • 輕量高效: 一個線程可以運行大量協程(掛起時釋放線程),資源開銷小。
      • 強大的生命周期集成: 通過 lifecycleScope/viewModelScope 自動取消,有效避免內存泄漏和無效 UI 更新。
      • 靈活的線程調度: 使用 withContext(Dispatcher) 在不同調度器間輕松切換。
      • 內置取消支持: 結構化并發和 Job.cancel() 使任務取消變得簡單可靠。
      • 異常處理: 提供 try/catchCoroutineExceptionHandler 處理異常。
    • 缺點:
      • 學習曲線: 需要理解 suspend、作用域、調度器、結構化并發等新概念。
      • Kotlin 專屬: Java 項目無法直接使用。
    • 適用場景: 現代 Android 開發中處理異步和并發的絕對首選! 幾乎適用于所有需要后臺處理或異步操作的地方,尤其適合網絡請求、數據庫操作、復雜流程編排等。
  6. 后臺任務調度:WorkManager

    • 原理: Jetpack 組件,用于可靠地執行可延期、保證執行的后臺任務。它兼容不同 API 級別,根據設備狀態(是否充電、是否有網絡、是否空閑)和設備重啟等因素智能調度任務執行。內部可能使用 JobScheduler, AlarmManager + BroadcastReceiverExecutor 實現。
    • 關鍵概念:
      • Worker: 定義要執行的任務邏輯(在 doWork() 中實現)。
      • WorkRequest: 描述任務的執行要求(約束、輸入數據、重試/退避策略、延遲、標簽等)。分為 OneTimeWorkRequestPeriodicWorkRequest
      • WorkManager:WorkRequest 加入隊列并調度執行。
      • 約束 (Constraints): 如網絡類型(UNMETERED)、充電狀態、設備空閑狀態、存儲空間等。
      • 鏈式任務: 支持順序或并行執行鏈。
    • 優點:
      • 可靠性: 保證任務最終會被執行,即使應用退出或設備重啟。
      • 兼容性: 自動選擇最佳底層實現。
      • 約束感知: 只在滿足條件(如聯網、充電)時執行。
      • 資源友好: 系統級調度,避免濫用資源。
      • 鏈式任務: 支持復雜工作流。
    • 缺點:
      • 不適用于即時任務: 執行時機由系統決定,無法精確控制(雖然有最小延遲,但不能保證立即執行)。
      • 不適合短時任務: 啟動開銷相對較大。
      • 不適合需要與用戶強交互的任務: 任務在后臺獨立運行。
    • 適用場景: 需要保證執行的后臺任務! 如日志上傳、數據同步、定期數據備份、通知內容預處理等。不是通用異步/多線程的替代品,而是特定場景的補充。

關鍵問題與最佳實踐:

  1. 線程安全與同步:

    • 共享可變狀態是萬惡之源: 盡可能避免在多個線程間共享可變數據。優先使用不可變數據、線程限制(如 ThreadLocal)或消息傳遞(Handler、協程 Channel/Flow)。
    • 同步機制:
      • synchronized: 方法或代碼塊級別的互斥鎖。簡單但粒度粗,易引發死鎖。
      • volatile: 保證變量的可見性(一個線程修改后其他線程立即可見),但不保證原子性(如 i++ 仍需同步)。
      • java.util.concurrent.locks.Lock (如 ReentrantLock): 提供比 synchronized 更靈活的鎖操作(可中斷、嘗試獲取鎖、公平鎖等)。
      • 原子類 (AtomicInteger, AtomicReference 等): 利用 CAS (Compare-And-Swap) 操作保證單個變量的原子性更新,無鎖,性能高。
      • 并發集合 (ConcurrentHashMap, CopyOnWriteArrayList): 內部實現了高效的并發控制,適合特定場景。
    • 最佳實踐: 優先考慮無鎖設計或使用高級并發工具。必須加鎖時,保持鎖的粒度盡可能小,持有鎖的時間盡可能短,并注意鎖的順序以避免死鎖。
  2. 內存泄漏:

    • 根源: 后臺線程(或 HandlerAsyncTask、未取消的協程)持有 Activity/Fragment/View 等 UI 組件的強引用,導致這些組件在生命周期結束后無法被 GC 回收。
    • 防范:
      • 使用弱引用 (WeakReference) 或軟引用 (SoftReference):Handler 或后臺任務中引用 UI 組件時。
      • 及時取消:onDestroy() 中取消后臺線程 (Thread.interrupt())、取消 AsyncTask (cancel(true))、取消協程作用域 (coroutineScope.cancel())。
      • 綁定生命周期: 強烈推薦使用 lifecycleScopeviewModelScope 啟動協程。 使用 WorkManager 處理持久化后臺任務。
      • 避免非靜態內部類: 內部類隱式持有外部類引用。優先使用靜態內部類或頂級類,并通過弱引用持有外部實例(如果需要)。
  3. 性能優化:

    • 選擇合適的線程模型: 理解任務類型(CPU/IO)并選擇相應調度器(協程)或配置線程池。
    • 限制并發: 使用線程池控制最大并發線程數,避免過度競爭 CPU 和內存資源。
    • 避免阻塞主線程: 時刻警惕,任何在主線程的耗時操作都是性能殺手和 ANR 的源頭。利用 StrictMode 檢測潛在問題。
    • 使用高效數據結構: 選擇適合并發訪問的數據結構(并發集合)。
    • 批處理: 對頻繁的小操作(如數據庫寫入)進行批處理,減少線程切換和同步開銷。
  4. 異常處理:

    • 后臺線程異常: 默認會導致線程終止且異常可能被吞掉。務必在 Runnable.run() 或協程內使用 try/catch 捕獲并妥善處理異常(記錄日志、通知用戶等)。為線程池設置 UncaughtExceptionHandler
    • 協程異常: 使用 try/catch 包裹 suspend 函數調用,或使用 CoroutineExceptionHandler(對 launch 有效)。注意 async 的異常在 await() 時拋出。

總結與推薦:

  • 理解主線程限制是基礎: 永遠不要在 UI 線程執行耗時操作。
  • 擁抱協程: 對于現代 Kotlin Android 開發,Kotlin 協程 (Coroutines) 是處理異步和并發的首選、最現代、最強大的解決方案。 結合 lifecycleScope/viewModelScopeDispatchers,能優雅地解決線程切換、生命周期管理和代碼可讀性問題。
  • 善用線程池 (Executor): 對于 Java 項目或不適合協程的場景,Executor 框架 (ThreadPoolExecutor) 是執行后臺任務的基石。 務必手動配置有界隊列和合適的拒絕策略。
  • 可靠后臺用 WorkManager: 對于需要保證執行、可延期、約束感知的后臺任務,使用 WorkManager
  • 徹底棄用 AsyncTask: 不要再在新項目中使用它。
  • 掌握 Handler 原理: 雖然直接使用頻率降低,但理解 Handler/Looper 機制對理解 Android 系統底層和協程調度原理仍有幫助。
  • 高度重視線程安全和同步: 謹慎處理共享數據,使用合適的同步機制。
  • 嚴防內存泄漏: 綁定生命周期、及時取消任務、使用弱引用。
  • 持續性能優化: 選擇合適的并發模型、控制并發度、避免阻塞主線程。

深度掌握 Android 多線程編程是一個持續學習和實踐的過程。理解不同方案的原理、優缺點和適用場景,并遵循最佳實踐,才能構建出既高效又健壯的 Android 應用。

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

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

相關文章

uniapp在app中關于解決輸入框鍵盤彈出后遮住輸入框問題

問題描述: uniapp的app中,當表單頁面過長時,點擊下方的輸入框時,彈出鍵盤后會把輸入框給擋住,導致看不到輸入內容。 解決方案: 在page.json中,找到此頁面的配置,加上style中的softin…

二分查找----5.尋找旋轉排序數組中的最小值

題目鏈接 /** 數組在某處進行旋轉,分割為兩個獨立的遞增區間,找出數組的最小值;特殊情況:若旋轉次數是數組長度的倍數,則數組不變 特點: 常規情況: 數組被分割為兩個獨立的子區間,左半區的最小值大于右半區的最大值 依據數組長度,mid可能落在左半區也有可能落在右半區,最小值在…

Eureka-服務注冊,服務發現

在遠程調用的時候&#xff0c;我們寫的url是寫死的。 String url "<http://127.0.0.1:9090/product/>" orderInfo.getProductId();當換個機器&#xff0c;或者新增個機器&#xff0c;導致ip變換&#xff0c;從而使得 url 發生了變化&#xff0c;接著就需要去…

ubuntu24的一些小問題

截圖Keyboard -> Keyboard Shortcus -> View and customize Shortcus如上&#xff0c;可以修改默認的快捷按鍵。比如截圖按鍵可以修改。 ibus輸入法無法&#xff0c;輸入V異常問題 也是困擾了很久&#xff0c;發現是這樣的&#xff1a;https://github.com/libpinyin/ibus…

Python Locust庫詳解:從入門到分布式壓力測試實戰

一、Locust核心優勢 作為一款基于Python的開源負載測試工具&#xff0c;Locust通過協程架構實現了高效資源利用。其獨特優勢體現在&#xff1a; 純Python腳本&#xff1a;用熟悉的語言定義用戶行為&#xff0c;支持條件判斷和復雜邏輯分布式擴展&#xff1a;單節點支持數千并發…

Redis數據類型與內部編碼

在Redis中通常普遍認為&#xff0c;使用redis的能進行查詢&#xff0c;插入&#xff0c;刪除&#xff0c;修改操作都是O(1)是因為他是利用hash表實現的&#xff0c;但是&#xff0c;背后的實現不一定是一個標準的hash表&#xff0c;它內部的數據類型還會有變數&#xff0c;不過…

03-netty基礎-多路復用select、poll、epoll

1 什么是多路復用多路復用&#xff08;Multiplexing&#xff09; 是一種讓單個線程同時處理多個 I/O 通道的技術&#xff0c;核心是通過系統調用將 I/O 狀態查詢的工作交給操作系統內核&#xff0c;應用程序只需等待內核通知哪些通道就緒。多路&#xff1a;指的是多個socket網絡…

網易大模型算法面經總結第一篇

網友一 MHA的原理&#xff0c;是如何進行加速的&#xff0c;用的什么框架推理。 回答&#xff1a; ①先答一下什么是MHA&#xff1a;Multi-Head Attention&#xff08;MHA&#xff09;是 Transformer 的核心機制&#xff0c;并行地關注輸入序列中不同位置的多種信息 ②回答MHA的…

Vue3 面試題及詳細答案120道(91-105 )

《前后端面試題》專欄集合了前后端各個知識模塊的面試題&#xff0c;包括html&#xff0c;javascript&#xff0c;css&#xff0c;vue&#xff0c;react&#xff0c;java&#xff0c;Openlayers&#xff0c;leaflet&#xff0c;cesium&#xff0c;mapboxGL&#xff0c;threejs&…

SAP-MM-物料進銷存表

ABAP庫存進銷存報表程序摘要 該ABAP程序是一個完整的庫存進銷存報表系統,主要功能包括: 報表類型選擇: 物料庫存進銷存 批次庫存進銷存 寄售庫存進銷存 供應商庫存進銷存 原料庫存進銷存 主要功能: 從歷史數據表(MARDH, MSKAH, MSLBH, MCHBH等)獲取期初庫存 處理物料移動數…

這幾天都是發癲寫的

#include <iostream> #include <vector> #include <unordered_map> #include <algorithm> #include <cmath> // for sqrt// Gen-Sort 實現&#xff08;保持不變&#xff09; void genSort(std::vector<int>& arr) {if (arr.empty()) r…

QT6 源,七章對話框與多窗體(11) 進度對話框 QProgressDialog:屬性,公共成員函數,槽函數,信號函數,與源代碼帶注釋

&#xff08;1&#xff09; 本類的繼承關系 &#xff1a;可見&#xff0c;進度對話框&#xff0c;也是 QDialog 的子類&#xff0c;在其上面又擺放了一些控件&#xff0c;構成了不同用途的對話框。咱們也可以自定義對話框。只是沒有 QT 官方大師們做的好。 人家在定義這 6 個子…

學習游戲制作記錄(技能系統)7.24

1.技能系統概念首先讓我們了解一下游戲的技能本質是什么&#xff0c;以投擲劍為例子&#xff0c;當玩家使用這個技能時&#xff0c;首先會播放玩家的動畫&#xff0c;隨后通過技能腳本創建一個劍的對象&#xff0c;當劍回收時會再次調用腳本&#xff0c;讓它朝向玩家飛來并銷毀…

外部存檔(External Archive)機制

前言 提醒&#xff1a; 文章內容為方便作者自己后日復習與查閱而進行的書寫與發布&#xff0c;其中引用內容都會使用鏈接表明出處&#xff08;如有侵權問題&#xff0c;請及時聯系&#xff09;。 其中內容多為一次書寫&#xff0c;缺少檢查與訂正&#xff0c;如有問題或其他拓展…

MybatisPlus操作方法詳細總結

摘要&#xff1a;本文圍繞 MyBatis-Plus 數據操作展開&#xff0c;涵蓋標準數據層 CRUD 與分頁查詢&#xff1b;以及各種的復雜 SQL 查詢&#xff1b;映射匹配&#xff08;TableField、TableName 注解&#xff09;與 ID 生成策略&#xff08;TableId 五種類型及全局配置&#x…

【C語言進階】動態內存管理的面試題||練習

本節內容專門整理了一些動態內存管理的面試題&#xff0c;配有詳細的解答。 目錄 1. 看代碼說結果 2. 看代碼說結果 3. 看代碼說結果 4.小樂樂與歐幾里得 描述 分析1&#xff1a; 分析2&#xff1a; 代碼&#xff1a; 5. 空心正方形 分析&#xff1a; 1. 看代碼說結…

【圖論】倍增與lca

void dfs(long u,long father){ dep[u]dep[father]1;//只在這里初始化depfor(long i1;(1<<i)<dep[u];i)fa[u][i]fa[fa[u][i-1]][i-1];//只這里用的倍增for(long ihead[u];~i;iedge[i].next){long vedge[i].to;if(vfather)continue;fa[v][0]u;dfs(v,u); }} long lca(lo…

VS Code 美化插件

目錄1. Better Comments 更好的注釋2. indent-rainbow 彩虹的縮進3. Trailing Spaces 尾隨的空格4. Gruvbox Material 護眼的材質5. Md Editor 博客編輯器6. 待補充推薦筆記&#xff1a;VS Code寫代碼必備的五款代碼美化插件 1. Better Comments 更好的注釋 Better Comments Be…

火語言 RPA 在日常運維中的實踐

在系統運維和技術支持工作中&#xff0c;總有一些操作像 “固定程序” 一樣循環往復&#xff1a;定期檢查服務器狀態、批量處理用戶權限申請、手動清理系統日志…… 這些工作步驟固定、邏輯簡單&#xff0c;卻占用了大量本可用于故障排查和系統優化的時間。近期在優化運維團隊的…

FOUPK3system5XOS系統 NTX V2.0發布通知

FOUPK3system5XOS系統NTX V2.0發布通知更新1.系統安全&#xff1a;使用FOUPK3system5XOS NOS X9新內核與FOUPK3system5XOS系統19.63正式版一樣提供更好的安全性2.原生應用&#xff1a;啟用FOUPK3system5XOS ONS X9 API 72服務FOUPK3system5XOS系統 NTX V2.0用戶支持使用FOUPK3…