Java中synchronized的用法,java集合 線程安全

 2023-12-06 阅读 27 评论 0

摘要:1.快速失敗(fail-fast)和安全失敗(fail-safe)? 一:快速失敗(fail—fast) 在用迭代器遍歷一個集合對象時,如果遍歷過程中對集合對象的內容進行了修改(增加、刪除、修改),則會拋出Concurrent Modification Exception。 原理&#

1.快速失敗(fail-fast)和安全失敗(fail-safe)?

一:快速失敗(fail—fast)

在用迭代器遍歷一個集合對象時,如果遍歷過程中對集合對象的內容進行了修改(增加、刪除、修改),則會拋出Concurrent Modification Exception。

原理:迭代器在遍歷時直接訪問集合中的內容,并且在遍歷過程中使用一個 modCount 變量。集合在被遍歷期間如果內容發生變化,就會改變modCount的值。每當迭代器使用hashNext()/next()遍歷下一個元素之前,都會檢測modCount變量是否為expectedmodCount值,是的話就返回遍歷;否則拋出異常,終止遍歷。

Java中synchronized的用法,注意:這里異常的拋出條件是檢測到 modCount!=expectedmodCount 這個條件。如果集合發生變化時修改modCount值剛好又設置為了expectedmodCount值,則異常不會拋出。因此,不能依賴于這個異常是否拋出而進行并發操作的編程,這個異常只建議用于檢測并發修改的bug。

場景:java.util包下的集合類都是快速失敗的,不能在多線程下發生并發修改(迭代過程中被修改)。

二:安全失敗(fail—safe)

采用安全失敗機制的集合容器,在遍歷時不是直接在集合內容上訪問的,而是先復制原有集合內容,在拷貝的集合上進行遍歷。

java的volatile?原理:由于迭代時是對原集合的拷貝進行遍歷,所以在遍歷過程中對原集合所作的修改并不能被迭代器檢測到,所以不會觸發Concurrent Modification Exception。

缺點:基于拷貝內容的優點是避免了Concurrent Modification Exception,但同樣地,迭代器并不能訪問到修改后的內容,即:迭代器遍歷的是開始遍歷那一刻拿到的集合拷貝,在遍歷期間原集合發生的修改迭代器是不知道的。

場景:java.util.concurrent包下的容器都是安全失敗,可以在多線程下并發使用,并發修改。

2.線程安全的java集合,以及其原理 (https://www.imooc.com/article/34600)

jdk1.5之前實現集合的并發開發和jdk1.5版本以后有所差別

Java線程安全相關的知識點?jdk1.5前:

  (1)最為簡單直接的就是在程序中我們自己對共享變量進行加鎖。不過,缺點也顯而易見,手動實現線程安全間接增加了程序的復雜度,以及代碼出錯的概率---例如:線程死鎖的產生;
  (2)我們還可以使用Java集合框架中的Vector、Hashtable實現類,這兩個類都是線程安全的。不過,Java已不提倡使用。
  (3)此外,我們還可以使用集合工具類--Collections,通過調用其中的靜態方法,來得到線程安全的集合。具體方法,包括:Collections.synchronizedCollection(Collection<T> c)、  Collections.synchronizedSet(Set<T> s)、Collections.synchronizedList(List<T>)、Collections.synchronizedMap(Map<K, V>)。
  究其原理,他們都是通過在方法中加synchronized同步鎖來實現的。我們知道synchronized鎖的開銷較大,在程序中不建議使用。
  雖然,這三種方式可以實現線程安全的集合,但是都有顯而易見的缺點,而且也不是我們今天所關注的重點。

jdk1.5推出了java.util.concurrent包。該包的出現,讓Java并發編程變得更加輕松,幫助開發者編寫更加高效、易維護、結構清晰的程序:

  阻塞式集合:當集合已滿或為空時,被調用的添加(滿)、移除(空)方法就不能立即被執行,調用這個方法的線程將被阻塞,一直等到該方法可以被成功執行。
  非阻塞式集合:當集合已滿或為空時,被調用的添加(滿)、移除(空)方法就不能立即被執行,調用這個方法的線程不會被阻塞,而是直接則返回null或拋出異常。

java線程安全類?下面,就來看下concurrent包下,到底存在了哪些線程安全的集合:
Collection集合:

List:
  CopyOnWriteArrayList
Set:
  CopyOnWriteArraySet
  ConcurrentSkipListSet
Queue:
  BlockingQueue:
  LinkedBlockingQueue
DelayQueue
  PriorityBlockingQueue
  ConcurrentLinkedQueue
TransferQueue:
  LinkedTransferQueue
  BlockingDeque:
  LinkedBlockingDeque
  ConcurrentLinkedDeque
Map集合:

Map:
  ConcurrentMap:
  ConcurrentHashMap
  ConcurrentSkipListMap
  ConcurrentNavigableMap
通過以上可以看出,java.util.concurrent包為每一類集合都提供了線程安全的實現。

其中list又采用的是CopyOnWrite機制,我對其理解是,這個機制與Array不同的是,其在get()方法中是不加鎖的,提升了性能.可以這么做的原因是,CopyOnWrite在add()的時候,既添加了鎖,又拷貝了備份,在備份上操作后又將指針指回原地址.

java讀寫鎖,簡單的理解,就是當我們往CopyOnWrite容器中添加元素時,不直接操作當前容器,而是先將容器進行Copy,然后對Copy出的新容器進行修改,修改后,再將原容器的引用指向新的容器,即完成了整個修改操作;

更詳細的解析需要到原博文去閱讀

?

?

轉載于:https://www.cnblogs.com/garfieldcgf/p/10283176.html

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://hbdhgg.com/1/189656.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 匯編語言學習筆記 Inc. 保留所有权利。

底部版权信息