概述
參考https://www.cnblogs.com/DreamRecorder/p/9223016.html
線程安全隊列可以分為,阻塞線程安全隊列和非阻塞線程安全隊列
阻塞線程安全隊列常用為ArrayBlockingQueue、LinkedBlockingQueue
非阻塞線程安全隊列一般為ConcurrentLinkedQueue
transient關鍵字
將不需要序列化的屬性前添加關鍵字transient,序列化對象的時候,這個屬性就不會被序列化。
1、transient底層實現原理是什么?
java的serialization提供了一個非常棒的存儲對象狀態的機制,說白了serialization就是把對象的狀態存儲到硬盤上 去,等需要的時候就可以再把它讀出來使用。有些時候像銀行卡號這些字段是不希望在網絡上傳輸的,transient的作用就是把這個字段的生命周期僅存於調用者的內存中而不會寫到磁盤里持久化,意思是transient修飾的age字段,他的生命周期僅僅在內存中,不會被寫到磁盤中。
2、被transient關鍵字修飾過得變量真的不能被序列化嘛?
實現了Externalizable接口,哪一個屬性被序列化使我們手動去指定的,即使是transient關鍵字修飾也不起作用。
靜態變量不管是不是transient關鍵字修飾,都不會被序列化
ArrayBlockingQueue
非阻塞方法,offer(e)、poll()公用同一個ReentrantLock,阻塞方法put(e)和take()采用ReentrantLock的兩個condition隊列分別用於交替喚醒。
LinkedBlockingQueue
LinkedBlockingQueue中用了兩個ReentrantLock,兩個ReentrantLock分別對應一個condition。
入隊操作其實操作的只有隊尾引用last,並且沒有牽涉到head。而出隊操作其實只針對head,和last沒有關系。那么就是說入隊和出隊的操作完全不需要公用一把鎖,所以就設計了兩個鎖,這樣就實現了多個不同任務的線程入隊的同時可以進行出隊的操作,另一方面由於兩個操作所共同使用的count是AtomicInteger類型的,所以完全不用考慮計數器遞增遞減的問題。
ConcurrentLinkedQueue
ConcurrentLinkedQueue是一個無鎖的並發線程安全的隊列。對比鎖機制的實現,使用無鎖機制的難點在於要充分考慮線程間的協調。簡單的說就是多個線程對內部數據結構進行訪問時,如果其中一個線程執行的中途因為一些原因出現故障,其他的線程能夠檢測並幫助完成剩下的操作。這就需要把對數據結構的操作過程精細的划分成多個狀態或階段,考慮每個階段或狀態多線程訪問會出現的情況。
ConcurrentLinkedQueue有兩個volatile的線程共享變量:head,tail。要保證這個隊列的線程安全就是保證對這兩個Node的引用的訪問(更新,查看)的原子性和可見性,由於volatile本身能夠保證可見性,所以就是對其修改的原子性要被保證。通過cas保證線程安全,實現較為復雜。
