參考路人甲java系列:https://www.cnblogs.com/itsoku123/p/11424473.html
12.4.3 狀態轉換、線程狀態的流轉
線程之間怎麼通訊的?
1、volatile修飾符:全局變量方式,最簡單的一種方法是使用全局變量
2、使用Object類的wait() 和 notify() 方法:Object類提供了線程間通信的方法:wait()、notify()、notifyaAl(),它們是多線程通信的基礎,而這種實現方式的思想自然是線程間通信。
3、JUC工具類 CountDownLatch:信號量等通知
4、使用 ReentrantLock 結合 Condition:
5、消息隊列
6 redis
?Volatile非原子性的原因?
----------高併發多線程----------
?多線程用到的場景?
1、前期的補償通知機制是用線程池newScheduledThreadPool 開啓的多線和去通知的。
2、上層來調網關的一些業務邏輯處理慢的接口,先快速返回,開啓線程異步處理業務邏輯,處理完了之後再通知上層業務方
3、mysql主從備份原理也是線程異步去實現的
-------------------ThreadLocal-------------
?ThreadLocal工作原理或實現原理?
https://www.cnblogs.com/kancy/p/10702310.html
底層也是封裝了ThreadLocalMap集合類來綁定當前線程和變量副本的關係,以threadlocal實例爲key,其他信息爲value,保證各個線程獨立並且訪問安全!
ThreadLocalMap
?ThreadLocal的作用或優點或應用場景?
Mybatis高併發數據庫連接操作,都會使用ThreadLocal類來保證Java多線程程序訪問和數據庫數據的一致性問題.
?我搭建過,如何搭建或如何使用?
-------------------Volatile-------------
?Volatile工作原理或實現原理?
?Volatile的作用或優點或應用場景?
作用是變量在多個線程之間可見,就可以通訊了
-------------------鎖-------------
1)wait方法----當interrupt方法遇到---嚴格不算是鎖
Object o= new Object();
try { o.wait();} catch (InterruptedException e) {}//thread裏執行了wait,釋放資源,wait進入等待隊列
wait(long)//過這個時間則自動喚醒。
thread.interrupt();//線程打斷interrupt喚醒wait
o.notify();//對象喚醒,調用notify()方法一次只隨機通知一個線程進行喚醒。
o.notifyAll();//對象喚醒,所有線程進行喚醒。
(sleep不需要喚醒,佔着資源呢)
2)synchronized 是一種悲觀鎖,阻塞的可重入鎖
synchronized (lock) {}
3)lock 是CAS(AQS)樂觀鎖,用tryLock方式是非阻塞的可重入鎖
private Lock lock = new ReentrantLock();
方式一: lock.lock();
方式二 : if (lock.tryLock()) { lock.lock(); try { } catch (Exception e) { } finally { lock.unlock(); }
?synchronized是線程安全的嗎?
是。線程安全性包括兩個方面,①可見性。②原子性。有的鎖可以用lock代替。
--------------------------------------------------------------------線程池--------------------------------------------------------------------
什麼是線程池
線程池是一個線程集合,線程池是運用場景最多的併發框架,需要異步或併發執行任務的程序都可以使用線程池。在開發過程中,合理地使用線程池能夠帶來3個好處。
第一:降低資源消耗。通過重複利用已創建的線程降低線程創建和銷燬造成的消耗。
第二:提高響應速度。當任務到達時,任務可以不需要等到線程創建就能立即執行。
第三:提高線程的可管理性。線程是稀缺資源,如果無限制地創建,不僅會消耗系統資源,
還會降低系統的穩定性,使用線程池可以進行統一分配、調優和監控。但是,要做到合理利用
線程池,必須對其實現原理了如指掌。
線程池作用
減少了創建和銷燬線程所需的時間,從而提高效率。
?巧記四種線程池?
1)公共創建頭:ExecutorService newExecutorService = Executors.new*Thread*--------EE
2)四種特殊線程池:------即ssfc(姍姍FC)
Single--------newSingleThreadExecutor總結:用唯一的工作線程來執行任務,結果依次輸出,相當於順序執行各個任務
S-------newScheduledThreadPool總結:定長線程池,支持定時及週期性任務執行
F---------newFixedThreadPool 總結:創建一個定長線程池,可控制線程最大併發數,超出的線程會在隊列中等待。
C-------------newCachedThreadPool 總結:線程池爲無限大,當執行第二個任務時第一個任務已經完成,會複用執行第一個任務的線程,而不用每次新建線程。
線程池原理剖析
提交一個任務到線程池中,線程池的處理流程如下:
1、判斷線程池裏的核心線程是否都在執行任務,如果不是(核心線程空閒或者還有核心線程沒有被創建)則創建一個新的工作線程來執行任務。如果核心線程都在執行任務,則進入下個流程。
2、線程池判斷工作隊列是否已滿,如果工作隊列沒有滿,則將新提交的任務存儲在這個工作隊列裏。如果工作隊列滿了,則進入下個流程。
3、判斷線程池裏的線程是否都處於工作狀態,如果沒有,則創建一個新的工作線程來執行任務。如果已經滿了,則交給飽和策略來處理這個任務。
合理配置線程池
要想合理的配置線程池,就必須首先分析任務特性,可以從以下幾個角度來進行分析:
任務的性質:CPU密集型任務,IO密集型任務和混合型任務。
任務的優先級:高,中和低。
任務的執行時間:長,中和短。
任務的依賴性:是否依賴其他系統資源,如數據庫連接。
任務性質不同的任務可以用不同規模的線程池分開處理。CPU密集型任務配置儘可能少的線程數量,如配置Ncpu+1個線程的線程池。IO密集型任務則由於需要等待IO操作,線程並不是一直在執行任務,則配置儘可能多的線程,如2*Ncpu。混合型的任務,如果可以拆分,則將其拆分成一個CPU密集型任務和一個IO密集型任務,只要這兩個任務執行的時間相差不是太大,那麼分解後執行的吞吐率要高於串行執行的吞吐率,如果這兩個任務執行時間相差太大,則沒必要進行分解。我們可以通過Runtime.getRuntime().availableProcessors()方法獲得當前設備的CPU個數。
優先級不同的任務可以使用優先級隊列PriorityBlockingQueue來處理。它可以讓優先級高的任務先得到執行,需要注意的是如果一直有優先級高的任務提交到隊列裏,那麼優先級低的任務可能永遠不能執行。
執行時間不同的任務可以交給不同規模的線程池來處理,或者也可以使用優先級隊列,讓執行時間短的任務先執行。
依賴數據庫連接池的任務,因爲線程提交SQL後需要等待數據庫返回結果,如果等待的時間越長CPU空閒時間就越長,那麼線程數應該設置越大,這樣才能更好的利用CPU。
一般總結哦,有其他更好的方式,希望各位留言,謝謝。
CPU密集型時,任務可以少配置線程數,大概和機器的cpu核數相當,這樣可以使得每個線程都在執行任務
IO密集型時,大部分線程都阻塞,故需要多配置線程數,2*cpu核數
操作系統之名稱解釋:
某些進程花費了絕大多數時間在計算上,而其他則在等待I/O上花費了大多是時間,
前者稱爲計算密集型(CPU密集型)computer-bound,後者稱爲I/O密集型,I/O-bound。
淺談Java中的深克隆和淺克隆
淺克隆:對於非基本類型字段屬性,只拷貝對象內存地址,修改該字段會影響原字段對象--類實現Cloneable接口
深克隆:對於非基本類型字段屬性,會重新創建一個對象,使用新的內存地址--實現clone()方法後,對非基本類型的對象類屬性字段,創建新對象,重新賦值
----------------併發包相關--------------------------------------
自旋鎖和互斥鎖的區別,java中lock Syncronized區別
1、自旋鎖---busy-waiting,自旋鎖是未獲得鎖的線程(對外被阻塞-但自旋鎖是一種非阻塞鎖,因爲它沒睡眠),但會死循環檢測,一直消耗cpu,直到獲得別人釋放的鎖(copy_to_user之類的接口可能造成死鎖)------無限檢測循環中,執行一個 CAS 操作,直到成功
2、互斥鎖---sleep-waiting,未獲得鎖的線程會sleep(被阻塞),放入等待隊列裏,直到獲得別人釋放的鎖--synchronized悲觀鎖
3、可重入鎖就是遞歸鎖,ReentrantLock和synchronized都是可重入鎖
4、公平鎖--公平鎖就是保障了多線程下各線程獲取鎖的順序,先到的線程優先獲取鎖,而非公平鎖則無法提供這個保障
5、可中斷鎖:顧名思義,就是可以相應中斷的鎖.synchronized就不是可中斷鎖,而Lock是可中斷鎖。lockInterruptibly()
?synchronized與ReentrantLock的區別?
same同點:
ReentrantLock和synchronized都是可重入鎖。
不同點:
synchronized是不可中斷鎖,而ReentrantLock則提供了中斷功能。
synchronized是非公平鎖,而ReentrantLock的默認實現是非公平鎖,但是也可以設置爲公平鎖
-----------ReentrantLock--------
名詞?
AQS--------------AbstractQueuedSynchronizer抽像隊列同步
CAS操作----------(CompareAndSwap)-比較和清除(巧記--比較抽象)
AQS使用一個FIFO的隊列表示排隊等待鎖的線程,包含:ReentrantLock,Semaphore,CountDownLatch,ReentrantReadWriteLock,FutureTask
CAS和AQS?(巧記--比較抽象)
一、CAS是CompareAndSwap-比較和清除, 比較舊值是否變化,變化則重新讀取再設置。,操作包含三個操作數——內存位置(V)、預期原值(A)和新值(B)。如果內存位置的值與預期原值相匹配,那麼處理器會自動將該位置值更新爲新值。否則,處理器不做任何操作。-----CAS操作保證修改狀態碼過程的原子性
二、AQS是AbstractQueuedSynchronizer 抽象隊列同步器,裏面有3個屬性:
int鎖狀態碼--從0變爲1表示加鎖成功;
當前加鎖線程--從Null變爲當前獲取鎖的線程;
一個等待隊列-----來存放多個等待線程。(使用volatile關鍵字保證狀態碼在線程間的可見性)
比如說ReentrantLock、ReentrantReadWriteLock等大多數併發包下的底層都是基於AQS來實現的。
1、AQS是CAS的基礎上增加一個隊列來放併發拿鎖失敗的等待線程,但默認false是不公平鎖,最後進的可能先拿到鎖。可設置屬性值ture改成公平鎖,
2、從ReentrantLock的加鎖和釋放鎖的過程,給大家講清楚了其底層依賴的AQS的核心原理:
這個講一下3個線程情況,線程1加鎖和釋放鎖的過程中,線程2、3是按順序還是不按順序,這個就有公平和非公平兩種鎖的場景
基於AQS框架實現的CountDownLatch和CyclicBarrier對比:
CountDownLatch維護有個int型的狀態碼,每次調用countDown時狀態值就會減1;調用wait方法的線程會阻塞,直到狀態碼爲0時纔會繼續執行。
CyclicBarrier可以實現CountDownLatch一樣的功能,不同的是CountDownLatch屬於一次性對象,聲明後只能使用一次,而CyclicBarrier可以循環使用。
總結#
CountDownLatch創建後只能使用一次,而CyclicBarrier可以循環使用,並且CyclicBarrier功能更完善。
CountDownLatch內部的狀態是基於AQS中的狀態信息,而CyclicBarrier中的狀態值是單獨維護的,使用ReentrantLock加鎖保證併發修改狀態值的數據一致性。
它們的使用場景:允許一個或多個線程等待其他線程完成操作, 即當指定數量線程執行完某個操作再繼續執行下一個操作
?ReentrantLock工作原理或實現原理?
ReentrantLock是Lock的默認實現之一。使用排隊等待鎖的機制,併發安全的
-----------CopyOnWriteArrayList--------
CopyOnWriteArrayList是線程安全List,適合----讀多寫少時且服務器內存夠用(CopyOnWrite併發容器用於讀多寫少的併發場景。比如白名單,黑名單等場景)
?CopyOnWriteArrayList工作原理或實現原理?
寫時是需要在方法內開始時,加ReentrantLock鎖的,避免多線程寫的時候會Copy出N個副本出來。
讀的時候不需要加鎖,因爲是安全失敗機制,寫的時候會複製新的副本,讀的是舊的副本,寫完會把引用改成改好的副本。,所以改成鎖讀依然讀到的是舊對象
快速失敗fail-fast----在A線程對集合進行遍歷的同時,B線程對集合進行了刪除操作,此時會拋出併發修改異常
安全失敗機制----集合在進行內容操作的時候,會先將集合內容複製一份,在新複製的集合上進行操作。所以當線程報錯的時候不會拋出異常
?的作用或優點或應用場景?
比如ArrayList,寫的時候,有人同時在讀,就會報併發修改異常---原因是
(Iterator 遍歷開始時,會把modCount記錄下來,循環結束時會比較一下這個值是否被改了,改動過就報異常)。
1)優點:所以和ArrayList比,CopyOnWriteArrayList採用安全失敗機制,先複製副本出來改副本,改的過程中,Iterator遍歷就不會報修改異常了。
1)缺點:對於業務來說,可能數據不一致,讀的是舊值。寫的時候,因爲要複製(當一個數組裏面數據量很大時,這時在複製一個副本就容易造成GC),還有加鎖,所以很慢。但查沒鎖沒複製,所以快。
應用場景----讀多寫少時且服務器內存夠用(複製佔內存),比如白名單,黑名單
?CopyOnWriteArrayList與Vector的區別?
1、Vector是比較古老的線程安全的,但性能不行,Vector讀寫方法上都是同步的(Synchronized),;
2、CopyOnWriteArrayList在兼顧了線程安全的同時,又提高了併發性,性能比Vector有不少提高----CopyOnWriteArrayList讀方法無讀;且寫方法內開始時,加ReentrantLock鎖後複製一個新副本出來記錄寫操作,之後再把引用指向新副本,釋放鎖。
?Vector & ArrayList ?
1) Vector的讀寫方法都是同步的(Synchronized),是線程安全的,但效率低
2) 擴容不一樣,Vector會將它的容量*2,而ArrayList只增加50%的大小。
?. Hashtable & HashMap
Hashtable和HashMap它們的性能方面的比較類似 Vector和ArrayList,比如Hashtable的方法是同步的,而HashMap的不是。
? ArrayList & LinkedList
ArrayList的內部實現是基於內部數組Object[],所以從概念上講,它更象數組,但LinkedList的內部實現是基於一組連接的記錄,所以,它更象一個鏈表結構,所以,它們在性能上有很大的差別:
?ArrayBlockingQueue、ConcurrentLinkedQueue 和 LinkedBlockingQueue
ArrayBlockingQueue是初始容量固定的阻塞隊列,我們可以用來作爲數據庫模塊成功競拍的隊列,比如有10個商品,那麼我們就設定一個10大小的數組隊列
ConcurrentLinkedQueue使用的是CAS原語無鎖隊列實現,是一個異步隊列,入隊的速度很快,出隊進行了加鎖,性能稍慢。
LinkedBlockingQueue是阻塞的隊列,入隊和出隊都用了加鎖,當隊空的時候線程會暫時阻塞
Synchronized和Lock比較?
- Synchronized是關鍵字,java內置語言實現,Lock是接口。(Java中每個對象都可以用來實現一個同步的鎖,這些鎖被稱爲內置鎖(Intrinsic Lock)或監視器鎖(Monitor Lock))----monitorenter 必須 有 對應 的 monitorexit
- Synchronized在線程發生異常時會自動釋放鎖,因此不會發生異常死鎖。Lock異常時不會自動釋放鎖,所以需要在finally中實現釋放鎖。
- Lock是可以中斷鎖,Synchronized是非中斷鎖,必須等待線程執行完成釋放鎖。
- Lock可以使用讀鎖提高多線程讀效率。