from中烟科技翼支付 面试题2
三、集合框架
- ArrayList, LinkedList, HashMap, LinkedHashMap, ConcurrentHashMap
的底层实现原理
ArrayList:动态数组,通过下标查询快,增加或者删除元素需要将元素后的所有元素挪一位,所以增删慢,大小满之后自动扩容1.5倍
linkedList:双向链表,需要遍历查询慢,只需要修改指针增删快
hashMap:数组+链表+红黑树,将数据根据哈希值存储到对应位置,如果有多个值存储为链表,如果链表过长存储为红黑树;数据达到大小*0.75触发扩容,扩容为两倍
linkedHashMap:在hashMap的基础上,使用双向链表保障数据的有序性
ConcurrentHashMap:线程安全的hashMap,通过 synchronized(锁桶/根节点/链表头) + CAS + volatile 实现了高并发下的高性能;put时如果位置已有数据使用synchronized锁住头节点,如果没有值使用cas自旋写入,get时使用volatile修饰实现数据可见。
-
1.7 版本和 1.8 版本的 HashMap 的区别
1.7存储结构使用数组+链表,当链表过长时,查询性能很差,1.8引入了红黑树存储,当链表过长使用红黑树存储,提高了查询速度;在扩容后1.7会重新计算每个值的哈希值并获取位置,性能较差,1.8使用规律算法,新的位置要么在原地要么是原位置+旧容量。 -
1.7 版本和 1.8 版本的 ConcurrentHashMap 的区别
1.8彻底放弃了1.7的分段锁,转而使用数组+链表+红黑树存储数据,并且通过synchronized锁头节点+CAS算法实现线程安全 -
HashMap 能不能排序?HashMap 的长度为什么要是 2 的幂次方?
hashMap是无序的,因为数据是根据哈希值确定的位置,不是根据集合下标的顺序存储的;2的幂次方可以方便进行迅速的扩容和已有数据的迁移。
四、多线程
5. 创建线程的几种方式?Wait,sleep 分别是谁的方法,区别?线程间的通信
方式?
extend Thread继承Thread类或者implements Runnable实现run方法,继承或者实现后需要重写run方法,run方法就是你要加的业务逻辑,使用start方法开始线程;或者使用Executor线程池。一般是用线程池,方便管理。
wait是Object的方法,sleep是Thread的方法;wait()方法必须在synchronized代码块中,否则会抛出异常,调用wait方法后,会释放掉对象锁,使其他线程能获取到该对象的对象锁,一直到使用notify()唤醒线程;使用sleep()会根据参数设置自动唤醒时间,而且sleep不会释放锁。
线程间的通信方式:多个线程共享同一份资源,同时使用synchronized来保证互斥,使用wait()释放锁,让其他线程获取锁和资源,等待其他线程使用完之后,通过notify()或者notifyAll()唤醒当前线程
blockingQueue阻塞队列,适用于生产者消费者模式(mq消息一般都是这种),设置一个队列,生产者往队列中写入数据,消费者从队列拉取数据,当队列满则阻塞,队列空也阻塞。
-
介绍下什么是死锁,遇见过死锁吗?你是怎么排查的。 (可以通过 jps 排查)
(未完待续) -
创建线程池的几种方式,线程池有什么好处
-
线程继承和接口的区别,接口有什么好处
-
Synchronized、Lock、ReentrantLock 的区别、用法及原理
-
CountDownLatch 与 CyclicBarrier 用法
-
ThreadLocal 的用法和原理
-
volatile 关键字的作用和原理
-
乐观锁和悲观锁
-
对公平锁、非公平锁、可重入锁、自旋锁,读写锁的理解
-
CAS 是什么底层原理
-
ArrayBlockingQueue,LinkedBlockingQueue,SynchronousQueue 等
等堵塞队列的理解 -
ThreadPoolExecutor 的传入参数及内部工作原理
-
给你一个具体的业务场景, 让你使用 ThreadPoolExecutor 创建一个适合的
线程池 -
分布式环境下,怎么保证线程安全
注意:问到的就是高并发