原文鏈接:為什麼 Go 語言 struct 要使用 tags 在 Go 語言中,struct 是一種常見的數據類型,它可以用來表示覆雜的數據結構。在 struct 中,我們可以定義多個欄位,每個欄位可以有不同的類型和名稱。 除了這些基本信息之外,Go 還提供了 struct tags,它可以用來指定 ...
進程與線程
進程,程式的一次執行過程,系統運行程式的基本單位。
啟動main函數,即啟動JVM的一個進程,mian函數為其主線程。
同類多個線程共用進程的堆和方法區資源,切換工作負擔比進程小。
一個Java程式的運行時main線程和多個其他線程同時運行。
各個進程是獨立的,但各個線程不一定,同一進程中線程會相互影響,線程執行開銷小,但不利於資源的管理和保護。
線程私有:PC,虛擬機棧,本地方法棧
PC:改變PC讀取指令,實現代碼流程式控制制(位元組碼解釋器);記錄當前線程執行的位置(多線程)
native方法,記錄undefined地址,Java代碼,下一條指令的地址
PC線程私有,便於線程切換後恢復到正確位置
虛擬機棧:Java方法,棧幀在虛擬機棧出入棧
本地方法棧:Native方法,本地方法棧初入棧
保證線程中局部變數不被其他線程訪問
堆和方法去(線程共用):
堆:存放新創建對象;方法區;存放類信息等
多線程好處:
線程切換和調度成本低,減少了上下文切換的開銷;多個同類線程之間的資源競爭較小,任務執行效率提高
多線程帶來的問題:
前文所講,線程執行開銷小,但不利於資源的管理和保護,記憶體泄漏,死鎖,線程不安全(之後可詳細討論)
線程生命周期和狀態:
只有六種,NEW,RUNNABLE,BLOCKED,WAITING,TIME_WAITING,TERMINATED,記憶時可以根據英文名稱記憶
註意區分阻塞狀態和等待狀態。
RUNNABLE狀態中包括運行中與就緒狀態,當就緒狀態的線程獲得時間片後變稱為運行狀態(因時間分片粒度很小,因此不做狀態區分了。
等待狀態的線程需要依靠其他線程的通知才能夠返回運行態,而超時等待的線程超過設置的時間後會自行返回到RUNNABLE狀態;阻塞狀態與鎖有關,鎖也是JAVA併發中的難點重點,後文會提及。
上下文切換:
上下文:線程執行過程中的運行條件和狀態(PC,棧信息等)
線程切換上下文時需保留當前線程的上下文(當線程下次占用CPU時恢復現場),載入下一個將要占用CPU的線程的上下文
保存信息回覆信息會占用CPU和記憶體資源,影響效率
線程死鎖:
多個線程同時被阻塞,等待資源的釋放,且占據著他們持有的資源(資源只能被一個線程占用)不釋放(別的線程無法強行剝奪),形成了一種迴圈等待資源的關係
預防避免線程死鎖:
破壞線程死鎖的條件(一次性申請所有資源,主動釋放占有的資源,按照某一順序申請資源(銀行家演算法))
Java中的鎖和監視器:
一直看到很多關於鎖和監視器的字眼,這次好好瞭解一下。
- Synchronization is built around an internal entity known as the intrinsic lock or monitor lock. (The API specification often refers to this entity simply as a "monitor.")
- Every object has an intrinsic lock associated with it. By convention, a thread has to acquire the object's monitor lock before accessing them, and then release the monitor lock when it's done with them. A thread is said to own the lock between the time it has acquired the lock and released the lock. As long as a thread owns a monitor lock, no other thread can acquire the same lock. The other thread will block when it attempts to acquire the lock.
- When a thread releases the lock, a happens-before relationship is established between that action and any subsequent acquisition of the same lock.
翻譯:
同步(synchronized)是圍繞一個內部實體建立的,被稱為內在鎖或監控鎖。(API規範經常把這個實體簡單地稱為 "監視器")。
每個對象都有一個與之相關的內在鎖。按照慣例,一個線程在訪問對象之前必須獲得對象的監控鎖,然後在使用完後釋放監控鎖。一個線程在獲得鎖和釋放鎖這段時間內被稱為擁有該鎖。只要一個線程擁有一個監控鎖,其他線程就不能獲得相同的鎖。當其他線程試圖獲取該鎖時,它將阻塞。
當一個線程釋放鎖的時候,在這個動作和任何後續的相同鎖的獲取之間建立了一個發生在之前的關係。
這是官方文檔裡面的,但還是有些晦澀,我沒太看懂