一、基礎普及
|
接口(interface) |
類(class) |
繼承類 |
實現的接口 |
Array |
√
|
|
|
|
Collection |
√ |
|
|
|
Set |
√ |
|
Collection |
|
List |
√ |
|
Collection |
|
Map |
√ |
|
Collection |
|
Vector |
|
√ |
|
List |
ArrayList |
|
√ |
|
List |
HashMap |
|
√ |
|
Map |
Hashtable |
|
√ |
Dictionary |
Map |
ConcurrentMap |
√ |
|
Map
|
|
ConcurrentHashMap
|
|
√ |
|
ConcurrentMap |
二、對比
1、HashMap與Hashtable區別
|
是否線程安全 |
允不允許null值 |
Hashtable |
線程安全。 因為里面的方法使用了synchronized進行同步 |
不允許。 key和value都不允許出現null值,否則會拋出NullPointerException異常。 |
HashMap |
非線程安全。 可以通過以下方式進行同步: Map m = Collections.synchronizeMap(hashMap); |
允許。 null可以作為鍵,這樣的鍵只有一個;可以有一個或多個鍵所對應的值為null。 |
Tip:
1、Hashtable是線程安全的,多個線程可以共享一個Hashtable;而如果沒有正確的同步的話,多個線程是不能共享HashMap的。Java 5提供了ConcurrentHashMap,它是HashTable的替代,比HashTable的擴展性更好。
2、由於Hashtable是線程安全的也是synchronized,所以在單線程環境下它比HashMap要慢。如果你不需要同步,只需要單一線程,那么使用HashMap性能要好過Hashtable。
2、Hashtable和ConcurrentHashMap在lock表區別圖
三、java並發包(java.util.concurrent)
1、線程池:
1.1、為什么要用到線程池
使用線程池的好處是減少在創建和銷毀線程上所花的時間以及系統資源的開銷,解決資源不足的問題。
如果不使用線程池,有可能造成系統創建大量同類線程而導致消耗完內存或者“過度切換”的問題。
1.2、線程池創建方式(常用)
1)固定數量的線程池newFixedThreadPool
int cpu = Runtime.getRuntime().availableProcessors();
final ExecutorService es = Executors.newFixedThreadPool(cpu);
2)可調度的線程池Scheduled Thread Pool :
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(4);
2、Java容器:
2.1、同步類容器
第一類:
同步類:Vector、Stack、Hashtable
非同步類:ArrayList、LinkedList、HashMap
第二類:Collections提供的一些工廠類(靜態)
2.2、並發類容器
java.util.concurrent提供了多種並發容器,總體上來說有4類:
- 隊列Queue類型的BlockingQueue和ConcurrentLinkedQueue
- Map類型的ConcurrentMap
- Set類型的ConcurrentSkipListSet和CopyOnWriteArraySet
- List類型的CopyOnWriteArrayList
在並發比較大的情況下,用ConcurrentMap來替代HashTable
使用CopyOnWriteArrayList替代Vector
2.3、concurrentHashMap
2.3.1、為什么采用concurrentHashMap:
Hashtable寫操作會鎖住整張表,效率低,寫操作無法並行
concurrentHashMap分成16個桶(把整張表分成16份),適合高並發
2.3.2、ConcurrentHashMap介紹:
ConcurrentHashMap采用了分段鎖的設計,只有在同一個分段內才存在競態關系,不同的分段鎖之間沒有鎖競爭。
相比於對整個Map加鎖的設計,分段鎖大大的提高了高並發環境下的處理能力。
2.3.3、Hashtable和ConcurrentHashMap在lock表區別圖
2.3.4、ConcurrentSkipListMap
跳表查詢,比ConcurrentHashMap效率快。
四、Java並發包消息隊列
1、BlockingQueue 阻塞隊列
主要的方法是:put、take一對阻塞存取;add、poll一對非阻塞存取。
put(anObject):把anObject加到BlockingQueue里,如果BlockQueue沒有空間,則調用此方法的線程被阻塞直到BlockingQueue里面有空間再繼續。
take():取走BlockingQueue里排在首位的對象,若BlockingQueue為空,阻斷進入等待狀態直到Blocking有新的對象被加入為止。
2、BlockingQueue成員介紹
2.1、ArrayBlockingQueue:
基於數組實現的有界阻塞隊列,查找快,增刪慢。生產者和消費者用的是同一把鎖,並發效率低
消費的方式:FIFO
2.2、LinkedBlockingQueue:
基於鏈表實現的阻塞隊列,鏈表是增刪快,定位慢,生產者和消費者用的鎖相互獨立,並發性能略高於ArrayBlockingQueue
2.3、DelayQueue(延時隊列):
DelayQueue中的元素,只有指定的延遲時間到了,才能夠從隊列中獲取到該元素。
DelayQueue是一個沒有大小限制的隊列,因此往隊列中插入數據的操作(生產者)永遠不會被阻塞,而只有獲取數據的操作(消費者)才會被阻塞
應用場景
1、客戶端長時間占用連接的問題,超過這個空閑時間了,可以移除的
2、處理長時間不用的緩存;如果隊列里面的對象長時間不用,超過了空閑時間,就移除
3、任務超時處理
2.4、PriorityBlockingQueue(優先級隊列):
PriorityBlockingQueue並不會阻塞數據生產者,而只會在沒有可消費的數據時,阻塞數據的消費者不阻塞生產者
compareTo()方法決定優先級。
2.5、SynchronousQueue(同步無緩沖隊列):
一種無緩沖的等待隊列,來一個任務就執行這個任務,這期間不能太添加任何的任務。也就是不用阻塞了,其實對於少量任務而言,這種做法更高效
聲明一個SynchronousQueue有兩種不同的方式,它們之間有着不太一樣的行為。
公平模式和非公平模式的區別:
如果采用公平模式:SynchronousQueue會采用公平鎖,並配合一個FIFO隊列來阻塞多余的生產者和消費者,從而體系整體的公平策略;
但如果是非公平模式(SynchronousQueue默認):SynchronousQueue采用非公平鎖,同時配合一個LIFO隊列來管理多余的生產者和消費者,而后一種模式,如果生產者和消費者的處理速度有差距,則很容易出現飢渴的情況,即可能有某些生產者或者是消費者的數據永遠都得不到處理。
2.5、concurrentLinkedQueue(高並發無鎖隊列)