只有光头才能变强。文本已收录至个人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文档的内容均为手打,有任何的不懂均可以直接来问我(公众号有个人联系方式)。