-
JAVA線程
-
java線程實現方式
- 實現runnable接口(無結果返回)
- 實現callable接口 (可以通過Future獲取返回執行結果)
- 直接繼承Thread類(爲一個實現runnable接口類的實例)
-
Java 創建線程代價
- 關於時間,創建線程使用是直接向系統申請資源的,這裏調用系統函數進行分配資源的話耗時不好說。對操作系統來說,創建一個線程的代價是十分昂貴的, 需要給它分配內存、列入調度,同時在線程切換的時候還要執行內存換頁,CPU 的緩存被 清空,切換回來的時候還要重新從內存中讀取信息,破壞了數據的局部性
- 關於資源,Java線程的線程棧所佔用的內存是在Java堆外的,所以是不受java程序控制的,只受系統資源限制,默認一個線程的線程棧大小是1M(當讓這個可以通過設置-Xss屬性設置,但是要注意棧溢出問題),但是,如果每個用戶請求都新建線程的話,1024個用戶光線程就佔用了1個G的內存,如果系統比較大的話,一下子系統資源就不夠用了,最後程序就崩潰了。
-
Java線程的狀態
- new(初始狀態) ---》 可運行(start|| submit) ----> 運行(獲得CPU使用權)---》 dead || 不可運行狀態
-
不可運行狀態 :
- 1,block 調用sleep || jion方法, 不會釋放線程monitor)放棄CPU使用權
- 2,lock 調用同步方法失敗,被放入到等待線程對列排隊. 繼續爭搶monitor權限。才能獲取自由freedom...
- 3,waiting 調用wait()方法, 放棄對象monitor權限, 被扔到等待對列, 等待notify方法, 或者notifyall()喚醒
-
dead
- 線程代碼執行結束或者出現異常退出,,,
-
線程池
-
存在的意義
- 降低使用線程代價,(節約系統創建線程, 銷燬線程的時間)
- a. 重用存在的線程,減少對象創建、消亡的開銷,性能佳。
- b. 可有效控制最大併發線程數,提高系統資源的使用率,同時避免過多資源競爭,避免堵塞。
- c. 提供定時執行、定期執行、單線程、併發數控制等功能。
- 線程池實現
-
原理
- 1、線程池管理器(ThreadPool):用於創建並管理線程池,包括 創建線程池,銷燬線程池,添加新任務;
- 2、工作線程(PoolWorker):線程池中線程,在沒有任務時處於等待狀態,可以循環的執行任務;
- 3、任務接口(Task):每個任務必須實現的接口,以供工作線程調度任務的執行,它主要規定了任務的入口,任務執行完後的收尾工作,任務的執行狀態等;
-
4、任務隊列(taskQueue):用於存放沒有處理的任務。提供一種緩衝機制。
- 常用線程池:ExecutorService 是主要的實現類,其中常用的有 : Executors.newSingleThreadPool() 之創建一個線程執行任務
newFixedThreadPool() 固定數目線程數
newcachedTheadPool() 使用時才創建線程
newScheduledThreadPool()
-
存在的意義
-
參考文檔鏈接地址
JAVA多線程同步
WHY-同步
- 因爲當我們有多個線程要同時訪問一個變量或對象時,如果這些線程中既有讀又有寫操作時,就會導致變量值或對象的狀態出現混亂,從而導致程序異常。舉個例子,如果一個銀行賬戶同時被兩個線程操作,一個取100塊,一個存錢100塊。假設賬戶原本有0塊,如果取錢線程和存錢線程同時發生,會出現什麼結果呢?取錢不成功,賬戶餘額是100.取錢成功了,賬戶餘額是0.那到底是哪個呢?很難說清楚。因此多線程同步就是要解決這個問題。
同步方式
-
1: synchronized 修飾方法
- 即有synchronized關鍵字修飾的方法。 由於java的每個對象都有一個內置鎖,當用此關鍵字修飾方法時,內置鎖會保護整個方法。在調用該方法前,需要獲得內置鎖,否則就處於阻塞狀態。
- Tips:synchronized關鍵字也可以修飾靜態方法,此時如果調用該靜態方法,將會鎖住整個類
-
2: synchronized 修飾代碼塊
- synchronized 修飾的邏輯越少代碼執行效率就越高(同步是一種高開銷的操作,因此應該儘量減少同步的內容。通常沒有必要同步整個方法,使用synchronized代碼塊同步關鍵代碼即可。)
-
3: 使用特殊域變量(Volatile)實現線程同步(該實現可能會有問題-- 加鎖機制既可以確保可見性又可以確保原子性,而volatile變量只有確保可見性。)
- a.volatile關鍵字爲域變量的訪問提供了一種免鎖機制
- b.使用volatile修飾域相當於告訴虛擬機該域可能會被其他線程更新
- c.因此每次使用該域就要重新計算,而不是使用寄存器中的值
-
d.volatile不會提供任何原子操作,它也不能用來修飾final類型的變量 (這點很關鍵, 它只能提供變量的原子訪問,可內存讀寫可見,但是不能保證操作數據過程的原子)
-
4: 使用重入鎖實現線程同步(ReentrantLock)
-
ReentrantLock類是可重入、互斥、實現了Lock接口的鎖, 它與使用synchronized方法和快具有相同的基本行爲和語義,並且擴展了其能力。ReenreantLock類的常用方法有:ReentrantLock() : 創建 ReentrantLock實例 lock() : 獲得鎖 unlock() : 釋放鎖
-
Tips:ReentrantLock()還有一個可以創建公平鎖的構造方法,但由於能大幅度降低程序運行效率,不推薦使用
-
-
(5)使用局部變量實現線程同步
- threadLocal
- 使的線程擁有變量私有備份,使用線程私有變量threadLocalMap 進行變量管理(使用Thread)。