標籤:操作 block 不可變 詳細介紹 互斥量 並發 原子變數 最大 策略
【java並發編程實戰】-----線程基本概念
線程狀態圖
說明:
線程共包括以下5種狀態。
1. 建立狀態(New) : 線程對象被建立後,就進入了建立狀態。例如,Thread thread = new Thread()。
2. 就緒狀態(Runnable): 也被稱為“可執行狀態”。線程對象被建立後,其它線程調用了該對象的start()方法,從而來啟動該線程。例如,thread.start()。處於就緒狀態的線程,隨時可能被CPU調度執行。
3. 運行狀態(Running) : 線程擷取CPU許可權進行執行。需要注意的是,線程只能從就緒狀態進入到運行狀態。
4. 阻塞狀態(Blocked) : 阻塞狀態是線程因為某種原因放棄CPU使用權,暫時停止運行。直到線程進入就緒狀態,才有機會轉到運行狀態。阻塞的情況分三種:
(01) 等待阻塞 -- 通過調用線程的wait()方法,讓線程等待某工作的完成。
(02) 同步阻塞 -- 線程在擷取synchronized同步鎖失敗(因為鎖被其它線程所佔用),它會進入同步阻塞狀態。
(03) 其他阻塞 -- 通過調用線程的sleep()或join()或發出了I/O請求時,線程會進入到阻塞狀態。當sleep()狀態逾時、join()等待線程終止或者逾時、或者I/O處理完畢時,線程重新轉入就緒狀態。
5. 死亡狀態(Dead) : 線程執行完了或者因異常退出了run()方法,該線程結束生命週期。
這5種狀態涉及到的內容包括Object類, Thread和synchronized關鍵字。這些內容我們會在後面的章節中逐個進行學習。
Object類,定義了wait(), notify(), notifyAll()等休眠/喚醒函數。
Thread類,定義了一些列的線程操作函數。例如,sleep()休眠函數, interrupt()中斷函數, getName()擷取線程名稱等。
synchronized,是關鍵字;它區分為synchronized代碼塊和synchronized方法。synchronized的作用是讓線程擷取對象的同步鎖。
在後面詳細介紹wait(),notify()等方法時,我們會分析為什麼“wait(), notify()等方法要定義在Object類,而不是Thread類中”。
在學習Java並發之前我們需要先理解一些基本的概念:共用、可變、執行緒安全性、線程同步、原子性、可見度、有序性。
共用和可變
要編寫安全執行緒的代碼,其核心在於對共用的和可變的狀態進行訪問。
“共用”就意味著變數可以被多個線程同時訪問。我們知道系統中的資源是有限的,不同的線程對資源都是具有著同等的使用權。有限、公平就意味著競爭,競爭就有可能會引發線程問題。
“可變”是指變數的值在其生命週期內是可以發生改變的。“可變”對應的是“不可變”。我們知道不可變的對象一定是安全執行緒的,並且永遠也不需要額外的同步(因為一個不可變的對象只要構建正確,其外部可見狀態永遠都不會發生改變)。所以“可變”意味著存線上程不安全的風險。解決辦法:
1、不線上程中共用該狀態變數,可以將變數封裝到方法中。
2、將狀態變數修改為不可變的變數(final)。
3、訪問狀態變數時使用同步策略。
4、使用原子變數類。
執行緒安全性
安全執行緒是一個比較複雜的概念。其核心概念就是正確性。所謂正確性就是某各類的行為與其規範完全一致,即其近似與“所見即所知(we know it when we see it)”。當多個線程訪問某各類時,不管運行時環境採用何種調度方式或者這些線程將如何交替執行,並且在主調代碼中不需要任何額外的同步或者協同,這個類都能表現出正確的行為,那麼就稱這個類是安全執行緒的。(引自:《Java並發編程實戰》)
線程同步
線程通過其核心就在於一個“同”。所謂“同”就是協同、協助、配合,“同步”就是協同步調昨,也就是按照預定的先後順序進行運行,即“你先,我等, 你做完,我再做”。
線程同步,就是當線程發出一個功能調用時,在沒有得到結果之前,該調用就不會返回,其他線程也不能調用該方法。就一般而言,我們在說同步、非同步時候,特指那些需要其他組件來配合或者需要一定時間來完成的任務。在多線程編程裡面,一些較為敏感的資料時不允許被多個線程同時訪問的,使用線程同步技術,確保資料在任何時刻最多隻有一個線程訪問,保證資料的完整性。
線程同步的機制主要有:臨界區、互斥量、事件、訊號量四種方式
1、臨界區:通過對多線程的序列化來訪問公用資源或一段代碼,速度快,適合控制資料訪問。在任意時刻只允許一個線程對共用資源進行訪問,如果有多個線程試圖訪問公用資源,那麼在有一個線程進入後,其他試圖訪問公用資源的線程將被掛起,並一直等到進入臨界區的線程離開,臨界區在被釋放後,其他線程才可以搶佔。
2、互斥量:採用互斥對象機制。 只有擁有互斥對象的線程才有訪問公用資源的許可權,因為互斥對象只有一個,所以能保證公用資源不會同時被多個線程訪問。互斥不僅能實現同一應用程式的公用資源安全共用,還能實現不同應用程式的公用資源安全共用。
3、訊號量:它允許多個線程在同一時刻訪問同一資源,但是需要限制在同一時刻訪問此資源的最大線程數目。
4、事 件: 通過通知操作的方式來保持線程的同步,還可以方便實現對多個線程的優先順序比較的操作。
【引自:百度百科】
原子性
原子是世界上最小的單位,具有不可分割性。在我們編程的世界裡,某個操作如果不可分割我們就稱之為該操作具有原子性。例如:i = 0,這個操作是不可分割的,所以該操作具有原子性。如果某個操作可以分割,那麼該操作就不具備原子性,例如i++。非原子操作都存線上程安全問題,這個時候我們需要使用同步機制來保證這些操作變成原子操作,來確保安全執行緒。
可見度
線程可見度是指線程之間的可見度,即一個線程對狀態的修改對另一個線程是可見的,也就是一個線程修改的結果,另外一個線程立馬就知道了。比如volitile修飾的變數,就具備可見度。
有序性
有序性指的是資料不相關的變數在並發的情況下,實際執行的結果和單線程的執行結果是一樣的,不會因為重排序的問題導致結果不可預知。volatile, final, synchronized,顯式鎖都可以保證有序性。
Java - 線程基本概念