標籤:
原文連結:http://segmentfault.com/q/1010000000370403
Java的目標是要跨平台,而不同的作業系統(如類Unix和Windows)其任務調度機制有很大的不同,故Java在JVM層面抽象了一套自己的線程機制,用以映射不同的作業系統的任務調度。如你所述的一些缺點,Java在1.1版本之後,這個線程模組就是基於核心層級線程[1]。
首先,如果一個機器上只有一個邏輯CPU,此時系統調度器通過輪換時間片的方式來調度任務,所以不存在真正的並行,只是並發;只有多個邏輯CPU的情形下,才會出現並行;
其次,對於不同的作業系統,其任務調度機制不同:
- 對於類Unix系統而言,一般都是進程作為任務的調度單位,也即是作業系統調度器,只會針對進程來分配CPU等資源。由於進程彼此獨立,相互不可進行直接存取,這增加了應用的通訊成本。所以後面有了微進程,微進程與進程不同的是,允許一定程度上,彼此可以直接進行訪問,詳細可參考LinuxThreads。JVM在一些類Unix平台下,就是將線程映射到作業系統的微進程,來實現線程調度。這樣多線程能夠直接被系統調度器進行調度,與此對應的就是其線程的建立和銷毀的成本就比較高,而且JVM的線程優先順序很難進行匹配,無法提供確切的保證,僅僅是個hint。需要說明的是在linux2.6之後,LinuxThreads被NPTL所取代,NPTL提供了1:1形式的執行緒模式,即每個線程一一對應一個核心調度實體,這樣即是核心層級的線程。同樣NPTL額外提供可替換的M:N模型Thread。
linux下jvm建立Thread的調用(openJDK-6-src-b27中的os_linux.cpp中的bool os::create_thread(Thread* thread, ThreadType thr_type, size_t stack_size)中調用以下API):
int ret = pthread_create(&tid, &attr, (void* (*)(void*)) java_start, thread);
具體的後續調用跟蹤,請參考pthread的實現;
- 對於Windows系統而言,從其一開始線程就是系統進行調度的最小單位,即Wiki[Thread]中所述的1:1模型。而對於使用者態線程和核心態線程,一般是針對N:1模型和M:N模型,即多個使用者態線程映射到一個核心線程,系統調度器的調度單位是核心態線程,對使用者態線程一無所知。個人對windows的執行緒模式不是十分瞭解,按照NPTL和Wiki[Thread]和中的描述,覺得windows直接將線程作為調度單位,不存在使用者態線程和核心態線程的區別。需要說明的是,JVM定義的線程優先順序和Windows的線程優先順序能夠很好地匹配。
windows下jvm建立Thread的調用-(openJDK-6-src-b27中的os_windows.cpp中的bool os::create_thread(Thread* thread, ThreadType thr_type, size_t stack_size)中調用以下API):
HANDLE thread_handle = (HANDLE)_beginthreadex(NULL, (unsigned)stack_size, (unsigned (__stdcall *)(void*)) java_start, thread, CREATE_SUSPENDED | STACK_SIZE_PARAM_IS_A_RESERVATION, &thread_id);
具體後續調用請參考windows的API;
最後,回答你的問題:
- Java的多線程不是騙人,針對不同的作業系統進行適配,確實實現了並發和並行;
- 使用者層級線程通常發生在進程層級,一般通過系統調用等不同的實現方式來類比實現並發,而核心層級線程則一般由系統的調度器來調度,是原生層級的並發;
- 核心層級線程有系統調度器調度,肯定可以享受多核的好處,而使用者層級線程是通過類比實現調度,由於其映射的調度實體(進程或者映射的核心級線程)才是系統調度器的調度單位,所以與核心級線程相比,其對資源的訪問確實存在一定的限制。詳細的內容或者想繼續深入瞭解,請再多參考參考wiki等文獻
【轉】java jvm 線程 與作業系統線程