只有光頭才能變強。文本已收錄至個人GitHub精選文章,歡迎Star:https://github.com/ZhongFuCheng3y/3yjava
Java集合是我認爲在Java基礎中最最重要的知識點了,Java集合是必須掌握的。我在實習/秋招面試的時候,只要是面到Java,那必定是少不了Java集合。git
做爲一個新人,最關心的其實有一點:這個技術在工做中是怎麼用的。換個說法:「工做中經常使用到的Java集合有哪些,應用場景是什麼」程序員
如何入門Java集合以及每一個經常使用的子類我在PDF整理好了,這就不粘貼過來了,有須要的就在PDF查看就行了。這份PDF絕對令你滿意。github
List集合下最多見的集合類有兩個:ArrayList和LinkedList面試
在工做中,我都是無腦用ArrayList。我問了兩個同事:「大家在項目中用過LinkedList嗎?」他們都表示沒有。算法
衆所周知,ArrayList底層是數組,LinkedList底層是鏈表。數組遍歷速度快,LinkedList增刪元素快。數據庫
爲何在工做中通常就用ArrayList,而不用LinkedList呢?緣由也很簡單:後端
copyOf()
被優化過,加上現代CPU對內存能夠塊操做,普通大小的ArrayList增刪比LinkedList更快。因此,在開發中,想到要用集合來裝載元素,第一個想到的就是ArrayList。數組
那麼來了,LinkedList用在什麼地方呢?咱們通常用在刷算法題上。把LinkedList當作一個先進先出的隊列,LinkedList自己就實現了Queue接口緩存
若是考慮線程安全的問題,能夠看看CopyWriteOnArrayList,實際開發用得很少,但我以爲能夠了解一下它的思想(CopyWriteOn),這個思想在Linux/文件系統都有用到。
Set集合下最多見的集合類有三個:HashSet、TreeSet、LinkedHashSet
List和Set都是集合,通常來講:若是咱們須要保證集合的元素是惟一的,就應該想到用Set集合
好比說:如今要發送一批消息給用戶,咱們爲了減小「一次發送重複的內容給用戶」這樣的錯誤,咱們就用Set集合來保存用戶的userId/phone
天然地,首先要保證最上游的那批用戶的userId/phone
是沒有重複的,而咱們用Set集合只是爲了作一個兜底來儘量避免重複發送的問題。
通常咱們在開發中最多用到的也就是HashSet。TreeSet是能夠排序的Set,通常咱們須要有序,從數據庫拉出來的數據就是有序的,可能每每寫order by id desc
比較多。而在開發中也不多管元素插入有序的問題,因此LinkedHashSet通常也用不上。
若是考慮線程安全的問題,能夠考慮CopyOnWriteArraySet,用得就更少了(這是一個線程安全的Set,底層實際上就是CopyWriteOnArrayList)
TreeSet和LinkedHashSet更多的可能用在刷算法的時候。
Map集合最多見的子類也有三個:HashMap、LinkedHashMap、TreeMap
若是考慮線程安全問題,應該想到的是ConcurrentHashMap,固然了Hashtable也要有必定的瞭解,由於面試實在是問得太多太多了。
HashMap在實際開發中用得也很是多,只要是key-value
結構的,通常咱們就用HashMap
。LinkedHashMap和TreeMap用的很少,緣由跟HashSet和TreeSet同樣。
ConcurrentHashMap在實際開發中也用得挺多,咱們不少時候把ConcurrentHashMap用於本地緩存,不想每次都網絡請求數據,在本地作本地緩存。監聽數據的變化,若是數據有變更了,就把ConcurrentHashMap對應的值給更新了。
不知道你們有沒有學過生產者和消費者模式,秋招面試的時候可能會讓你手寫一段這樣的代碼。最簡單的方式就是用阻塞隊列去寫。相似下面:
生產者:
import java.util.Random; import java.util.Vector; import java.util.concurrent.atomic.AtomicInteger; public class Producer implements Runnable { // true--->生產者一直執行,false--->停掉生產者 private volatile boolean isRunning = true; // 公共資源 private final Vector sharedQueue; // 公共資源的最大數量 private final int SIZE; // 生產數據 private static AtomicInteger count = new AtomicInteger(); public Producer(Vector sharedQueue, int SIZE) { this.sharedQueue = sharedQueue; this.SIZE = SIZE; } @Override public void run() { int data; Random r = new Random(); System.out.println("start producer id = " + Thread.currentThread().getId()); try { while (isRunning) { // 模擬延遲 Thread.sleep(r.nextInt(1000)); // 當隊列滿時阻塞等待 while (sharedQueue.size() == SIZE) { synchronized (sharedQueue) { System.out.println("Queue is full, producer " + Thread.currentThread().getId() + " is waiting, size:" + sharedQueue.size()); sharedQueue.wait(); } } // 隊列不滿時持續創造新元素 synchronized (sharedQueue) { // 生產數據 data = count.incrementAndGet(); sharedQueue.add(data); System.out.println("producer create data:" + data + ", size:" + sharedQueue.size()); sharedQueue.notifyAll(); } } } catch (InterruptedException e) { e.printStackTrace(); Thread.currentThread().interrupted(); } } public void stop() { isRunning = false; } }
消費者:
import java.util.Random; import java.util.Vector; public class Consumer implements Runnable { // 公共資源 private final Vector sharedQueue; public Consumer(Vector sharedQueue) { this.sharedQueue = sharedQueue; } @Override public void run() { Random r = new Random(); System.out.println("start consumer id = " + Thread.currentThread().getId()); try { while (true) { // 模擬延遲 Thread.sleep(r.nextInt(1000)); // 當隊列空時阻塞等待 while (sharedQueue.isEmpty()) { synchronized (sharedQueue) { System.out.println("Queue is empty, consumer " + Thread.currentThread().getId() + " is waiting, size:" + sharedQueue.size()); sharedQueue.wait(); } } // 隊列不空時持續消費元素 synchronized (sharedQueue) { System.out.println("consumer consume data:" + sharedQueue.remove(0) + ", size:" + sharedQueue.size()); sharedQueue.notifyAll(); } } } catch (InterruptedException e) { e.printStackTrace(); Thread.currentThread().interrupt(); } } }
Main方法測試:
import java.util.Vector; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class Test2 { public static void main(String[] args) throws InterruptedException { // 1.構建內存緩衝區 Vector sharedQueue = new Vector(); int size = 4; // 2.創建線程池和線程 ExecutorService service = Executors.newCachedThreadPool(); Producer prodThread1 = new Producer(sharedQueue, size); Producer prodThread2 = new Producer(sharedQueue, size); Producer prodThread3 = new Producer(sharedQueue, size); Consumer consThread1 = new Consumer(sharedQueue); Consumer consThread2 = new Consumer(sharedQueue); Consumer consThread3 = new Consumer(sharedQueue); service.execute(prodThread1); service.execute(prodThread2); service.execute(prodThread3); service.execute(consThread1); service.execute(consThread2); service.execute(consThread3); // 3.睡一下子而後嘗試中止生產者(結束循環) Thread.sleep(10 * 1000); prodThread1.stop(); prodThread2.stop(); prodThread3.stop(); // 4.再睡一下子關閉線程池 Thread.sleep(3000); // 5.shutdown()等待任務執行完才中斷線程(由於消費者一直在運行的,因此會發現程序沒法結束) service.shutdown(); } }
個人項目用阻塞隊列也挺多的(我以爲跟我的編寫的代碼風格習慣有關),相似實現了上面的生產者和消費者模式。
真實場景例子:
好處是什麼?我在取userId的時候,會有個限制:要麼超出了指定的時間,要麼達到BatchSize的值。這樣我就能夠將相同內容的不一樣userId組成一個Task。
原本100個userId是100個Task,如今我將100個userId放在一個Task裏邊(由於發送的內容是相同的,因此我能夠這麼幹)。這樣再往下游傳的時候,併發量就下降了不少。
何時考慮線程安全的集合類,那固然是線程不安全的時候咯。那何時線程不安全?最多見的是:操做的對象是有狀態的
雖說,咱們常常會聽到線程不安全,但在業務開發中要咱們程序員處理線程不安全的地方少之又少。好比說:你在寫Servlet的時候,加過syn/lock
鎖嗎?應該沒有吧?
由於咱們的操做的對象每每是無狀態的。沒有共享變量被多個線程訪問,天然就沒有線程安全問題了。
SpringMVC是單例的,但SpringMVC都是在方法內操做數據的,每一個線程進入方法都會生成棧幀,每一個棧幀的數據都是線程獨有的,若是不設定共享變量,不會有線程安全問題。
上面只是簡單舉了SpringMVC的例子(只是爲了更好的理解);
一句話總結:只要涉及到多個線程操做一個共享變量的時候,就要考慮是否是要用線程安全的集合類。
更多的細節,等我寫Java多線程總結的時候再說了
仍是想強調一下,Java集合雖然在工做中不是每一個都常常用獲得,可是仍是得重點學習學習。
若是你學習到了源碼,可能你在建立集合的時候就會指定了集合的大小(即使咱們知道它能動態擴容)
若是你想要去面試,Java集合是確定少不了的,必問的一個知識點,你學會了就是送分題。
如今已經工做有一段時間了,爲何還來寫Java集合
呢,緣由有如下幾個:
read.me
會常常更換。如今的GitHub導航也不合我心意了(太長了),而且早期的文章,說實話排版也不太行,我決定從新搞一波。基於上面的緣由,我決定把個人系列文章彙總成一個PDF/HTML/WORD
文檔。說實話,打造這麼一個文檔花了我很多的時間。爲了防止白嫖,關注個人公衆號回覆「888」便可獲取。
PDF的內容很是很是長,乾貨很是很是的硬,有興趣的同窗能夠「白嫖」一波。記住:Java集合在Java的知識處於一個很是重要的知識點,建議掌握!
文檔的內容均爲手打,有任何的不懂均可以直接來問我(公衆號有個人聯繫方式)。
上一期的「JSP」的PDF在公衆號差點意思,目標是180個在看,雖然沒達到,但我仍是帶着黑眼圈來了。
JSP的PDF有人會說:『大人,時代變了』,我就不信Java集合還有人對我說『大人,時代變了』
若是此次在看超過200,那下週再肝一個系列出來。想要看什麼,能夠留言告訴我
若是你們想要實時關注我更新的文章以及分享的乾貨的話,微信搜索Java3y。
PDF文檔的內容均爲手打,有任何的不懂均可以直接來問我(公衆號有個人聯繫方式)。