Android 如何保證并發場景下class只會被加載一次?

本文基于Android10的classlinker的源碼,分析了linker對于class加載是怎么保證并發安全的。

簡化DefineClass流程

ObjPtr<mirror::Class> ClassLinker::DefineClass() { 
  auto klass = hs.NewHandle<mirror::Class>(nullptr);
  //分配一個Class的空間
  klass.Assign(AllocClass(self, SizeOfClassWithoutEmbeddedTables(dex_file, dex_class_def)));
  //注冊dex file,這一步不會重復注冊,就不再分析了
  ObjPtr<mirror::DexCache> dex_cache = RegisterDexFile(*new_dex_file, class_loader.Get());
  //對klass加鎖
  ObjectLock<mirror::Class> lock(self, klass);
  //安裝class,把class的基本信息設置好
  SetupClass(*new_dex_file, *new_class_def, klass, class_loader.Get());
  //注冊到ClassTable,后續就可以直接從table里面找了
  ObjPtr<mirror::Class> existing = InsertClass(descriptor, klass.Get(), hash);
  if (existing != nullptr) {
    // We failed to insert because we raced with another thread. Calling EnsureResolved may cause
    // this thread to block.
    return EnsureResolved(self, descriptor, existing);
  }
  //加載
  LoadClass();
  //鏈接
  LinkClass();
  //...
}

重點一、InsertClass

InsertClass函數

重點二、EnsureResolved

InsertClass()執行結束之后,klass還會經過加載、鏈接、初始化流程,如何確保最終返回的class經過了這些流程呢?
根據重點一,可知DefineClass()方法中的ObjectLock<mirror::Class> lock(self, klass)同樣會持有klass的鎖直到DefineClass方法的結束。而EnsureResolved恰好利用了這一點,讓其它線程通過競爭klass鎖的方式,確保klass的Define流程結束:

EnsureResolved關鍵代碼

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容