Java架構直通車——爲什麼線程切換會導致用戶態與內核態的切換?

什麼是上下文切換?上下文切換的時機?

CPU通過分配時間片來執行任務,當一個任務的時間片用完,就會切換到另一個任務。在切換之前會保存上一個任務的狀態,當下次再切換到該任務,就會加載這個狀態。
——任務從保存到再加載的過程就是一次上下文切換。

按導致上下文切換的因素劃分,可將上下文切換分爲兩點:

  1. 自發性上下文切換
  2. 非自發性上下文切換

自發性上下文切換指線程由於自身因素導致的切出。

通過調用下列方法會導致自發性上下文切換:
Thread.sleep()
Object.wait()
Thread.yeild()
Thread.join()
LockSupport.park()

非自發性上下文切換指線程由於線程調度器的原因被迫切出。

發生下列情況可能導致非自發性上下文切換:
切出線程的時間片用完
有一個比切出線程優先級更高的線程需要被運行
虛擬機的垃圾回收動作

上下文切換的開銷

上下文切換的開銷包括直接開銷和間接開銷。
直接開銷有如下幾點:

  1. 操作系統保存回覆上下文所需的開銷
  2. 線程調度器調度線程的開銷

間接開銷有如下幾點:

  1. 處理器高速緩存重新加載的開銷
  2. 上下文切換可能導致整個一級高速緩存中的內容被沖刷,即被寫入到下一級高速緩存或主存

互斥鎖與自旋鎖

重量級鎖需要通過操作系統自身的互斥量(mutex lock,也稱爲互斥鎖)來實現,然而這種實現方式需要通過用戶態與和核心態的切換來實現,但這個切換的過程會帶來很大的性能開銷。

申請鎖時,從用戶態進入內核態,申請到後從內核態返回用戶態(兩次切換);沒有申請到時阻塞睡眠在內核態。使用完資源後釋放鎖,從用戶態進入內核態,喚醒阻塞等待鎖的進程,返回用戶態(又兩次切換);被喚醒進程在內核態申請到鎖,返回用戶態(可能其他申請鎖的進程又要阻塞)。所以,使用一次鎖,包括申請,持有到釋放,當前進程要進行四次用戶態與內核態的切換。同時,其他競爭鎖的進程在這個過程中也要進行一次切換。

自旋鎖與互斥鎖不同的是自旋鎖不會引起調用者睡眠。如果自旋鎖已經被別的進程保持,調用者就輪詢(不斷的消耗CPU的時間)是否該自旋鎖的保持者已經釋放了鎖("自旋"一詞就是因此而得名)。

爲什麼線程切換會導致用戶態與內核臺的切換?

現在來回答就很簡單了:
因爲線程的調度是在內核態運行的,而線程中的代碼是在用戶態運行。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章