Android Systrace 基礎知識(9)-MainThread 和 RenderThread 解讀

2021-03-02 Android Performance

本文是 Systrace 系列文章的第九篇,主要是是介紹 Android App 中的 MainThread 和 RenderThread,也就是大家熟悉的「主線程」「渲染線程」。文章會從 Systrace 的角度來看 MainThread 和 RenderThread 的工作流程,以及涉及到的相關知識:卡頓、軟體渲染、掉幀計算等

本系列的目的是通過 Systrace 這個工具,從另外一個角度來看待 Android 系統整體的運行,同時也從另外一個角度來對 Framework 進行學習。也許你看了很多講 Framework 的文章,但是總是記不住代碼,或者不清楚其運行的流程,也許從 Systrace 這個圖形化的角度,你可以理解的更深入一些

系列文章目錄Systrace 基礎知識 - MainThread 和 RenderThread 解讀[9]Systrace 基礎知識 - Binder 和鎖競爭解讀[10]Systrace 基礎知識 - Triple Buffer 解讀[11]Systrace 基礎知識 - CPU Info 解讀[12]正文

這裡以滑動列表為例 ,我們截取主線程和渲染線程「一幀」的工作流程(每一幀都會遵循這個流程,不過有的幀需要處理的事情多,有的幀需要處理的事情少) ,重點看 「UI Thread 」 和 RenderThread 這兩行

App 一幀的工作流

「這張圖對應的工作流程如下」

主線程處於 Sleep 狀態,等待 Vsync 信號Vsync 信號到來,主線程被喚醒,Choreographer 回調 FrameDisplayEventReceiver.onVsync 開始一幀的繪製處理 App 這一幀的 Input 事件(如果有的話)處理 App 這一幀的 Animation 事件(如果有的話)處理 App 這一幀的 Traversal 事件(如果有的話)主線程與渲染線程同步渲染數據,同步結束後,主線程結束一幀的繪製,可以繼續處理下一個 Message(如果有的話,IdleHandler 如果不為空,這時候也會觸發處理),或者進入 Sleep 狀態等待下一個 Vsync渲染線程首先需要從 BufferQueue 裡面取一個 Buffer(dequeueBuffer) , 進行數據處理之後,調用 OpenGL 相關的函數,真正地進行渲染操作,然後將這個渲染好的 Buffer 還給 BufferQueue (queueBuffer) , SurfaceFlinger 在 Vsync-SF 到了之後,將所有準備好的 Buffer 取出進行合成(這個流程在講 SurfaceFlinger 的時候會提到)

上面這個流程在 Android 基於 Choreographer 的渲染機制詳解[13] 這篇文章裡面已經介紹的很詳細了,包括每一幀的 doFrame 都在做什麼、卡頓計算的原理、APM 相關. 沒有看過這篇文章的同學,建議先去掃一眼

那麼這篇文章我們主要從 Android 基於 Choreographer 的渲染機制詳解[14] 這篇文章沒有講到的幾個點來入手,幫你更好地理解主線程和渲染線程

主線程的創建

Android App 的進程是基於 Linux 的,其管理也是基於 Linux 的進程管理機制,所以其創建也是調用了 fork 函數

frameworks/base/core/jni/com_android_internal_os_Zygote.cpp

pid_t pid = fork();

Fork 出來的進程,我們這裡可以把他看做主線程,但是這個線程還沒有和 Android 進行連接,所以無法處理 Android App 的 Message ;由於 Android App 線程運行「基於消息機制」 ,那麼這個 Fork 出來的主線程需要和 Android 的 Message 消息綁定,才能處理 Android App 的各種 Message

這裡就引入了 「ActivityThread」 ,確切的說,ActivityThread 應該起名叫 ProcessThread 更貼切一些。ActivityThread 連接了 Fork 出來的進程和 App 的 Message ,他們的通力配合組成了我們熟知的 Android App 主線程。所以說 ActivityThread 其實並不是一個 Thread,而是他初始化了 Message 機制所需要的 MessageQueue、Looper、Handler ,而且其 Handler 負責處理大部分 Message 消息,所以我們習慣上覺得 ActivityThread 是主線程,其實他只是主線程的一個邏輯處理單元。

ActivityThread 的創建

App 進程 fork 出來之後,回到 App 進程,查找 ActivityThread 的 Main函數

com/android/internal/os/ZygoteInit.java

static final Runnable childZygoteInit(
int targetSdkVersion, String[] argv, ClassLoader classLoader) {
RuntimeInit.Arguments args = new RuntimeInit.Arguments(argv);
return RuntimeInit.findStaticMain(args.startClass, args.startArgs, classLoader);
}

這裡的 startClass 就是 ActivityThread,找到之後調用,邏輯就到了 ActivityThread的main函數

android/app/ActivityThread.java

public static void main(String[] args) {
//1. 初始化 Looper、MessageQueue
Looper.prepareMainLooper();
// 2. 初始化 ActivityThread
ActivityThread thread = new ActivityThread();
// 3. 主要是調用 AMS.attachApplicationLocked,同步進程信息,做一些初始化工作
thread.attach(false, startSeq);
// 4. 獲取主線程的 Handler,這裡是 H ,基本上 App 的 Message 都會在這個 Handler 裡面進行處理
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
// 5. 初始化完成,Looper 開始工作
Looper.loop();
}

注釋裡面都很清楚,這裡就不詳細說了,main 函數處理完成之後,主線程就算是正式上線開始工作,其 Systrace 流程如下:

主線程工作流ActivityThread 的功能

另外我們經常說的,Android 四大組件都是運行在主線程上的,其實這裡也很好理解,看一下 ActivityThread 的 Handler 的 Message 就知道了

class H extends Handler { //摘抄了部分
public static final int BIND_APPLICATION = 110;
public static final int EXIT_APPLICATION = 111;
public static final int RECEIVER = 113;
public static final int CREATE_SERVICE = 114;
public static final int STOP_SERVICE = 116;
public static final int BIND_SERVICE = 121;
public static final int UNBIND_SERVICE = 122;
public static final int DUMP_SERVICE = 123;
public static final int REMOVE_PROVIDER = 131;
public static final int DISPATCH_PACKAGE_BROADCAST = 133;
public static final int DUMP_PROVIDER = 141;
public static final int UNSTABLE_PROVIDER_DIED = 142;
public static final int INSTALL_PROVIDER = 145;
public static final int ON_NEW_ACTIVITY_OPTIONS = 146;
}

可以看到,進程創建、Activity 啟動、Service 的管理、Receiver 的管理、Provider 的管理這些都會在這裡處理,然後進到具體的 handleXXX

主線程的工作渲染線程的創建和發展

主線程講完了我們來講渲染線程,渲染線程也就是 RenderThread ,最初的 Android 版本裡面是沒有渲染線程的,渲染工作都是在主線程完成,使用的也都是 CPU ,調用的是 libSkia 這個庫,RenderThread 是在 Android Lollipop 中新加入的組件,負責承擔一部分之前主線程的渲染工作,減輕主線程的負擔

軟體繪製

我們一般提到的硬體加速,指的就是 GPU 加速,這裡可以理解為用 RenderThread 調用 GPU 來進行渲染加速 。硬體加速在目前的 Android 中是默認開啟的, 所以如果我們什麼都不設置,那麼我們的進程默認都會有主線程和渲染線程(有可見的內容)。我們如果在 App 的 AndroidManifest 裡面,在 Application 標籤裡面加一個

android:hardwareAccelerated="false"

我們就可以關閉硬體加速,系統檢測到你這個 App 關閉了硬體加速,就不會初始化 RenderThread ,直接 cpu 調用 libSkia 來進行渲染。其 Systrace 的表現如下

純軟體渲染

與這篇文章開頭的開了硬體加速的那個圖對比,可以看到主線程由於要進行渲染工作,所以執行的時間變長了,也更容易出現卡頓,同時幀與幀直接的空閒間隔也變短了,使得其他 Message 的執行時間被壓縮

硬體加速繪製

正常情況下,硬體加速是開啟的,主線程的 draw 函數並沒有真正的執行 drawCall ,而是把要 draw 的內容記錄到 DIsplayList 裡面,同步到 RenderThread 中,一旦同步完成,主線程就可以被釋放出來做其他的事情,RenderThread 則繼續進行渲染工作

硬體加速渲染渲染線程初始化

渲染線程初始化在真正需要 draw 內容的時候,一般我們啟動一個 Activity ,在第一個 draw 執行的時候,會去檢測渲染線程是否初始化,如果沒有則去進行初始化

android/view/ViewRootImpl.java

mAttachInfo.mThreadedRenderer.initializeIfNeeded(
mWidth, mHeight, mAttachInfo, mSurface, surfaceInsets);

後續直接調用 draw

android/graphics/HardwareRenderer.java

mAttachInfo.mThreadedRenderer.draw(mView, mAttachInfo, this);
void draw(View view, AttachInfo attachInfo, DrawCallbacks callbacks) {
final Choreographer choreographer = attachInfo.mViewRootImpl.mChoreographer;
choreographer.mFrameInfo.markDrawStart();

updateRootDisplayList(view, callbacks);

if (attachInfo.mPendingAnimatingRenderNodes != null) {
final int count = attachInfo.mPendingAnimatingRenderNodes.size();
for (int i = 0; i < count; i++) {
registerAnimatingRenderNode(
attachInfo.mPendingAnimatingRenderNodes.get(i));
}
attachInfo.mPendingAnimatingRenderNodes.clear();
attachInfo.mPendingAnimatingRenderNodes = null;
}

int syncResult = syncAndDrawFrame(choreographer.mFrameInfo);
if ((syncResult & SYNC_LOST_SURFACE_REWARD_IF_FOUND) != 0) {
setEnabled(false);
attachInfo.mViewRootImpl.mSurface.release();
attachInfo.mViewRootImpl.invalidate();
}
if ((syncResult & SYNC_REDRAW_REQUESTED) != 0) {
attachInfo.mViewRootImpl.invalidate();
}
}

上面的 draw 只是更新 DIsplayList ,更新結束後,調用 syncAndDrawFrame ,通知渲染線程開始工作,主線程釋放。渲染線程的核心實現在 libhwui 庫裡面,其代碼位於 frameworks/base/libs/hwui

frameworks/base/libs/hwui/renderthread/RenderProxy.cpp

int RenderProxy::syncAndDrawFrame() {
return mDrawFrameTask.drawFrame();
}

關於 RenderThread 的工作流程這裡就不細說了,後續會有專門的篇幅來講解這個,目前 hwui 這一塊的流程也有很多優秀的文章,大家可以對照文章和源碼來看,其核心流程在 Systrace 上的表現如下:

渲染線程核心方法主線程和渲染線程的分工

主線程負責處理進程 Message、處理 Input 事件、處理 Animation 邏輯、處理 Measure、Layout、Draw ,更新 DIsplayList ,但是不涉及 SurfaceFlinger 打交道;渲染線程負責渲染渲染相關的工作,一部分工作也是 CPU 來完成的,一部分操作是調用 OpenGL 函數來完成的

當啟動硬體加速後,在 Measure、Layout、Draw 的 Draw 這個環節,Android 使用 DisplayList 進行繪製而非直接使用 CPU 繪製每一幀。DisplayList 是一系列繪製操作的記錄,抽象為 RenderNode 類,這樣間接的進行繪製操作的優點如下

DisplayList 可以按需多次繪製而無須同業務邏輯交互特定的繪製操作(如 translation, scale 等)可以作用於整個 DisplayList 而無須重新分發繪製操作當知曉了所有繪製操作後,可以針對其進行優化:例如,所有的文本可以一起進行繪製一次可以將對 DisplayList 的處理轉移至另一個線程(也就是 RenderThread)主線程在 sync 結束後可以處理其他的 Message,而不用等待 RenderThread 結束

RenderThread 的具體流程大家可以看這篇文章 :http://www.cocoachina.com/articles/35302[15]

遊戲的主線程與渲染線程

遊戲大多使用單獨的渲染線程,有單獨的 Surface ,直接跟 SurfaceFlinger 進行交互,其主線程的存在感比較低,絕大部分的邏輯都是自己在自己的渲染線程裡面實現的。

大家可以看一下王者榮耀對應的 Systrace ,重點看應用進程和 SurfaceFlinger 進程(30fps)

王者榮耀

可以看到王者榮耀主線程的主要工作,就是把 Input 事件傳給 Unity 的渲染線程,渲染線程收到 Input 事件之後,進行邏輯處理,畫面更新等。

FlutterFlutter 的主線程和渲染線程

這裡提一下 Flutter App 在 Systrace 上的表現,由於 Flutter 的渲染是基於 libSkia 的,所以它也沒有 RenderThread ,而是他自建的 RenderEngine , Flutter 比較重要的兩個線程是 ui 線程和 gpu 線程,對應到下面提到的  Framework 和 Engine 兩層

Flutter

Flutter 中也會監聽 Vsync 信號 ,其 VsyncView 中會以 postFrameCallback 的形式,監聽 doFrame 回調,然後調用 nativeOnVsync ,將 Vsync  到來的信息傳給 Flutter UI 線程,開始一幀的繪製。

Flutter

可以看到 Flutter 的思路跟遊戲開發的思路差不多,不依賴具體的平臺,自建渲染管道,更新快,跨平臺優勢明顯。

Flutter SDK 自帶 Skia 庫,不用等系統升級就可以用到最新的 Skia 庫,而且 Google 團隊在 Skia 上做了很多優化,所以官方號稱性能可以媲美原生應用

Flutter

Flutter 的框架分為 Framework 和 Engine 兩層,應用是基於 Framework 層開發的,Framework 負責渲染中的 Build,Layout,Paint,生成 Layer 等環節。Engine 層是 C++實現的渲染引擎,負責把 Framework 生成的 Layer 組合,生成紋理,然後通過 Open GL 接口向 GPU 提交渲染數據。

Flutter

當需要更新 UI 的時候,Framework 通知 Engine,Engine 會等到下個 Vsync 信號到達的時候,會通知 Framework,然後 Framework 會進行 animations, build,layout,compositing,paint,最後生成 layer 提交給 Engine。Engine 會把 layer 進行組合,生成紋理,最後通過 Open Gl 接口提交數據給 GPU,GPU 經過處理後在顯示器上面顯示。整個流程如下圖:

Flutter性能

如果主線程需要處理所有任務,則執行耗時較長的操作(例如,網絡訪問或資料庫查詢)將會阻塞整個界面線程。一旦被阻塞,線程將無法分派任何事件,包括繪圖事件。主線程執行超時通常會帶來兩個問題

卡頓:如果主線程 + 渲染線程每一幀的執行都超過 16.6ms(60fps 的情況下),那麼就可能會出現掉幀。卡死:如果界面線程被阻塞超過幾秒鐘時間(根據組件不同 , 這裡的閾值也不同),用戶會看到 「應用無響應[16]」 (ANR) 對話框(部分廠商屏蔽了這個彈框,會直接 Crash 到桌面)

對於用戶來說,這兩個情況都是用戶不願意看到的,所以對於 App 開發者來說,兩個問題是發版本之前必須要解決的,ANR 這個由於有詳細的調用棧,所以相對來說比較好定位;但是間歇性卡頓這個,可能就需要使用工具來進行分析了:Systrace + TraceView,所以理解主線程和渲染線程的關係和他們的工作原理是非常重要的,這也是本系列的一個初衷

另外關於卡頓,可以參考下面三篇文章,你的 App 卡頓不一定是你 App 的問題,也有可能是系統的問題,不過不管怎麼說,首先要會分析卡頓問題。

Android 中的卡頓丟幀原因概述 - 方法論[17]Android 中的卡頓丟幀原因概述 - 系統篇[18]Android 中的卡頓丟幀原因概述 - 應用篇[19]參考https://juejin.im/post/5a9e01c3f265da239d48ce32[20]http://www.cocoachina.com/articles/35302[21]https://juejin.im/post/5b7767fef265da43803bdc65[22]http://gityuan.com/2019/06/15/flutter_ui_draw/[23]https://developer.android.google.cn/guide/components/processes-and-threads[24]附件

本文涉及到的附件也上傳了,各位下載後解壓,使用 「Chrome」 瀏覽器打開即可

點此連結下載文章所涉及到的 Systrace 附件[25]

關於我 && 博客關於我[26] , 非常希望和大家一起交流 , 共同進步 .優秀博客文章記錄 - Android 性能優化必知必會[28]

「一個人可以走的更快 , 一群人可以走的更遠」

Reference[1]

Systrace 簡介: https://www.androidperformance.com/2019/05/28/Android-Systrace-About/

[2]

Systrace 基礎知識 - Systrace 預備知識: https://www.androidperformance.com/2019/07/23/Android-Systrace-Pre/

[3]

Systrace 基礎知識 - Why 60 fps ?: https://www.androidperformance.com/2019/05/27/why-60-fps/

[4]

Systrace 基礎知識 - SystemServer 解讀: https://www.androidperformance.com/2019/06/29/Android-Systrace-SystemServer/

[5]

Systrace 基礎知識 - SurfaceFlinger 解讀: https://www.androidperformance.com/2020/02/14/Android-Systrace-SurfaceFlinger/

[6]

Systrace 基礎知識 - Input 解讀: https://www.androidperformance.com/2019/11/04/Android-Systrace-Input/

[7]

Systrace 基礎知識 - Vsync 解讀: https://www.androidperformance.com/2019/12/01/Android-Systrace-Vsync/

[8]

Systrace 基礎知識 - Vsync-App :基於 Choreographer 的渲染機制詳解: https://androidperformance.com/2019/10/22/Android-Choreographer/

[9]

Systrace 基礎知識 - MainThread 和 RenderThread 解讀: https://www.androidperformance.com/2019/11/06/Android-Systrace-MainThread-And-RenderThread/

[10]

Systrace 基礎知識 - Binder 和鎖競爭解讀: https://www.androidperformance.com/2019/12/06/Android-Systrace-Binder/

[11]

Systrace 基礎知識 - Triple Buffer 解讀: https://www.androidperformance.com/2019/12/15/Android-Systrace-Triple-Buffer

[12]

Systrace 基礎知識 - CPU Info 解讀: https://www.androidperformance.com/2019/12/21/Android-Systrace-CPU

[13]

Android 基於 Choreographer 的渲染機制詳解: https://www.androidperformance.com/2019/10/22/Android-Choreographer/

[14]

Android 基於 Choreographer 的渲染機制詳解: https://www.androidperformance.com/2019/10/22/Android-Choreographer/

[15]

http://www.cocoachina.com/articles/35302: http://www.cocoachina.com/articles/35302

[16]

應用無響應: http://developer.android.google.cn/guide/practices/responsiveness.html

[17]

Android 中的卡頓丟幀原因概述 - 方法論: https://www.androidperformance.com/2019/09/05/Android-Jank-Debug/

[18]

Android 中的卡頓丟幀原因概述 - 系統篇: https://www.androidperformance.com/2019/09/05/Android-Jank-Due-To-System/

[19]

Android 中的卡頓丟幀原因概述 - 應用篇: https://www.androidperformance.com/2019/09/05/Android-Jank-Due-To-App/

[20]

https://juejin.im/post/5a9e01c3f265da239d48ce32: https://juejin.im/post/5a9e01c3f265da239d48ce32

[21]

http://www.cocoachina.com/articles/35302: http://www.cocoachina.com/articles/35302

[22]

https://juejin.im/post/5b7767fef265da43803bdc65: https://juejin.im/post/5b7767fef265da43803bdc65

[23]

http://gityuan.com/2019/06/15/flutter_ui_draw/: http://gityuan.com/2019/06/15/flutter_ui_draw/

[24]

https://developer.android.google.cn/guide/components/processes-and-threads: https://developer.android.google.cn/guide/components/processes-and-threads

[25]

點此連結下載文章所涉及到的 Systrace 附件: https://github.com/Gracker/SystraceForBlog/tree/master/Android_Systrace-MainThread-RenderThread

[26]

關於我: https://www.androidperformance.com/about/

[27]

博客內容導航: https://androidperformance.com/2019/12/01/BlogMap/

[28]

優秀博客文章記錄 - Android 性能優化必知必會: https://androidperformance.com/2018/05/07/Android-performance-optimization-skills-and-tools/

相關焦點

  • Android Systrace 基礎知識(12) - Kernel_CPU Info 解讀
    : https://www.androidperformance.com/2019/05/27/why-60-fps/[4]Systrace 基礎知識 - SystemServer 解讀: https://www.androidperformance.com/2019/06/29/Android-Systrace-SystemServer/[5]Systrace 基礎知識
  • Android Systrace 基礎知識(10) - Binder 和鎖競爭解讀
    系列文章目錄Systrace 基礎知識 - Binder 和鎖競爭解讀[10]Systrace 基礎知識 - Triple Buffer 解讀[11]Systrace 基礎知識 - CPU Info 解讀[12]Binder 概述Android 的大部分進程間通信都使用 Binder,這裡對 Binder 不做過多的解釋,想對 Binder
  • Android Systrace 基礎知識(5) - SurfaceFlinger 解讀
    [5]Systrace 基礎知識 - SystemServer 解讀[6]Systrace 基礎知識 - SurfaceFlinger 解讀[7]Systrace 基礎知識 - Input 解讀[8]Systrace 基礎知識 - Vsync 解讀[9]Systrace 基礎知識 - Vsync-App :基於 Choreographer 的渲染機制詳解[10]Systrace 基礎知識 - MainThread
  • Android Systrace 基礎知識(7) - Vsync 解讀
    [3]Systrace 基礎知識 - SystemServer 解讀[4]Systrace 基礎知識 - SurfaceFlinger 解讀[5]Systrace 基礎知識 - Input 解讀[6]Systrace 基礎知識 - Vsync 解讀[7]Systrace 基礎知識 - Vsync-App :基於 Choreographer 的渲染機制詳解[8]Systrace 基礎知識 - MainThread
  • ActivityThread的main方法究竟做了什麼?
    Android應用程式的載體是 APK文件,它本質上,是一個資源和組件的容器,APK文件 和我們常見的 可執行文件 的區別在何處?當然Android除了繼承從 Zygote 中得到的某些基礎的「家當」之外,Android還需要在應用的 Java層 建立一套框架來管理運行的組件。由於每個應用的配置都不相同,因此不能在 Zygote 中完全建立好再繼承,只能在應用啟動時創建。
  • UNIX(多線程):03--- 認識std::thread
    構造和賦值std::thread 構造函數默認構造函數 (1)thread() noexcept;初始化構造函數 (2)template <class Fn, class...#include <iostream>#include <thread>#include <chrono>void foo(){std::this_thread::sleep_for(std::chrono::seconds(1)); }int main(){std::thread
  • 多線程編程(1):從thread開始,邁入多線程的大門
    /thread      thread: thread: 12 // 兩個線程的輸出融合在一起了,                   work in main thread      thread: 0          // 最先啟動的線程,卻最後輸出      main thread end    // 子線程都已中止
  • RT_Thread系統使用總結
    #幸福和幸運是需要代價的,天下沒有免費的午餐!
  • C++11並發編程:多線程std::thread
    << endl;}int main(){    thread t1(threadFun1);    t1.join();    getchar();    return 1;}2.創建線程,傳參void threadFun1(int v){    cout
  • ​一幀圖像的Android之旅:SurfaceFlinger初見
    = 0;    renderEngineFeature |= (useColorManagement ?                            renderengine::RenderEngine::USE_COLOR_MANAGEMENT : 0);    renderEngineFeature |= (useContextPriority ?
  • RT-Thread移植到nRF52840
    》(下載地址-複製至外部瀏覽器打開:https://www.rt-thread.org/document/site/submodules/rtthread-manual-doc/README/)以及火哥的《RT-Thread 內核實現與應用開發實戰—基於STM32》(本公眾號後臺回覆:野火RT-Thread 即可下載),本書的重點還是側重藍牙理論和實戰
  • Android開發:HandlerThread是什麼?
    介於這兩者之間,Google工程師又貼心的為我們提供了一個輕量級的HandlerThread,可以用來執行多個耗時操作,而不需要多次開啟、關閉線程,內部是將Thread和Handler進行封裝實現。話不多說,直接上代碼,使用HandlerThread來執行耗時任務,看看是否優雅。
  • Java 並發編程:深入剖析 ThreadLocal
    初始時,在Thread裡面,threadLocals為空,當通過ThreadLocal變量調用get()方法或者set()方法,就會對Thread類中的threadLocals進行初始化,並且以當前ThreadLocal變量為鍵值,以ThreadLocal要保存的副本變量為value,存到threadLocals。
  • 詳解Java中ThreadLocal類型
    = new ThreadLocal();private static void print(String thread) { //列印當前線程中本地內存中本地變量的值 System.out.println(thread + " :" + threadLocal.get()); //清除本地內存中的本地變量 threadLocal.remove
  • Android Systrace 基礎知識(6) - Input 解讀
    系列文章目錄Systrace 基礎知識 - Vsync-App :基於 Choreographer 的渲染機制詳解Systrace 基礎知識 - MainThread 和 RenderThread 解讀Systrace 基礎知識 - Binder 和鎖競爭解讀Systrace 基礎知識 - Triple Buffer 解讀Systrace 基礎知識 - CPU Info 解讀正文
  • Java8線程池ThreadPoolExecutor底層原理及其源碼解析
    小侃一下日常開發中, 或許不會直接new線程或線程池, 但這些線程相關的基礎或思想是非常重要的, 參考林迪效應;就算沒有直接用到, 可能間接也用到了類似的思想或原理, 例如tomcat, jetty, 資料庫連接池, MQ;本文不會對線程的基礎知識進行介紹
  • JNI-Thread中start方法調用與run方法回調分析
    我們查看該.h文件,其中就包含了jniHello方法的定義,當然需要注意到的是,這裡的方法名和.h文件本身的命名是jni根據我們類的包名和類名確定出來的,不能修改。創建如下的.c文件,在main方法中創建一個線程,並讓2個線程不斷列印一些文案#include <pthread.h>#include <stdio.h>pthread_t pid;void* thread_entity(void* arg){ while (1) { printf("i am thread\n"); }}
  • 使用Executors,ThreadPoolExecutor,創建線程池,源碼分析理解
    java.util.concurrent.TimeUnit;/*** 描述:** @author yanpenglei* @create 2017-10-12 15:39**/public class TestThreadPoolExecutor {public static void main
  • RT-Thread教程一之Linux下開發環境及QEMU配置
    RT-Thread原始碼Linux下安裝git後在工程目錄下(比~/Workplace)執行git clone https://github.com/RT-Thread/rt-thread我們看一下樹目錄結構rt-thread
  • 【RT-Thread Studio入門】使用輪詢法檢測按鍵
    \n"); 6 7/* 判斷線程是否啟動成功 */ 8if( rt_err == RT_EOK) 9    rt_kprintf("key thread startup ok. \n");10else11    rt_kprintf("key thread startup err.