高并发学习(二)安全发布对象/不可变对象/线程封闭
線程安全的途徑:
?
安全發布對象-發布與逃逸
- 發布對象:使一個對象能夠被當前范圍之外的代碼所使用
- 對象逃逸:一種錯誤的發布。當一個對象還沒有構造完成的,就使它被其他線程所見?
安全發布對象(單例模式:列一下)
單例模式中的枚舉方式是最安全的,雙重鎖的時候加volitale關鍵字才是線程安全的。
- 在靜態初始化函數中初始化一個對象引用
- 將對象的引用保存到volatile類型或者AtomicReference對象中
- 將對象的引用保存到某個正確構造對象的final類型域中
- 將對象的引用保存到鎖保護的域中
躲避并發(1.不可變對象2.線程封閉)
不可變對象
- 對象創建之后其狀態就不能修改
- 對象所有域都是final類型
- 對象是正確創建的(在創建期間,this引用沒有逃逸)
final關鍵字:類、方法、變量
修飾類:不能被繼承
修飾方法:1、鎖定方法不能被繼承類修改;2、效率
修飾變量:基本數據類型變量、引用類型變量
其他不可變對象:(多線程情況下不會有線程安全的問題了)
Collections.unmodeifiableXXX:Collection,List,Set,Map,,,
Guava:ImmutableXXX:Collection、List、Set、Map
?
線程封閉
threadlocal(看源碼):
線程局部變量,ThreadLocal實例通常來說都是private static類型的。ThreadLocal可以給一個初始值,而每個線程都會獲得這個初始值的一個副本,這樣就能保證不同的線程都有一個拷貝(每個拷貝之間相互沒有影響)
解決:
1.多線程中相同變量的訪問沖突問題。
2.數據庫連接,先判斷connThreadLocal.get()是否為null,如果是null,則說明當前線程還滅有對應的Connection對象,這時創建一個Coonection對象并添加到本地線程變量中;如果不為null,則說明當前線程已經擁有了Connection對象,直接使用就可以了。
//其中public Object get()該方法返回當前線程所對應的線程局部變量。
?
preHandler
afterHandler
?
線程不安全的類的寫法:
Stringbuilder類:不安全
StringBuffer類:近乎所有方法都加了sychronized的方法
SimpleDateFormat類:不安全
?DateTime類(joda-time):安全
同步容器:
ArrayList(不同步)-》Vector,Stack(同步)
HashMap-》HashTable(key、value不能為null)(同步)
Collections.synchronizedXXX(List、Set、Map)(同步)
?
eg.對集合中的元素進行刪除,不建議在foreach循環和利用iterator的過程中進行刪除,建議先進行標記,標記之后再進行刪除。
?
并發容器JUC:
ArrayList->CopyOnWriteArrayList(寫的使用開辟內存(復制),且用了lock鎖)
- 缺點:1.內存2.不能實時讀,只能最終一致性(適合讀多寫少)
- 性質:讀寫分離,最終一致性,寫的時候開辟空間
HashSet、TreeSet->CopyOnWriteArraySet
ConcurrentSkipListSet
HashMap、TreeMap->ConcurrentHashMap(效率是ConcurrentSkipListMap的4倍)
ConcurrentSkipListMap(key有序,支持比ConcurrentHashMap并發性更高)
轉載于:https://www.cnblogs.com/nickup/p/9695386.html
總結
以上是生活随笔為你收集整理的高并发学习(二)安全发布对象/不可变对象/线程封闭的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【linux下dhcp服务的简单搭建及优
- 下一篇: Gradle task