2018年3月9日16时08分接到阿里Java实习生电话面试,进行了48分钟,记录如下:
自我介绍
多线程几种实现方式
- 继承
Thread
类创建线程 - 实现
Callable
接口创建线程 - 实现
Runnable
接口创建新线程
进程和线程的状态
- 进程:创建、就绪、执行、阻塞、终止
- 线程:就绪、执行、阻塞
synchronized
和Lock
synchronized
是一种同步锁,可用于修饰方法、对象、类、代码块,是关键字。而Lock
是一个接口synchronized
是隐式锁,在需要同步的对象中加入此控制,而Lock
是显示锁,需要显示指定起始位置和终止位置- 使用
Lock
时在finally
中必须释放锁,不然容易造成线程死锁;而使用synchronized
时,获取锁的线程会在执行完同步代码后释放锁(或者JVM
会在线程执行发生异常时释放锁) - 使用
Lock
时线程不会一直等待;而使用synchronized
时,假设A线程获得锁后阻塞,其他线程会一直等待 Lock
可重入、可中断、可公平也可不公平;而synchronized
可重入但不可中断、非公平
锁的类型
- 可重入锁(
synchronized
和ReentrantLock
都是可重入锁) - 可中断锁(
synchronized
就不是可中断锁,而Lock
是可中断锁) - 公平锁(以请求锁的顺序来获取锁)
- 读写锁(
ReadWriteLock
就是读写锁,ReentrantReadWriteLock
实现了这个接口)
死锁避免
- 加锁顺序(线程按一定顺序加锁,若所有线程都按相同顺序获得锁,就能避免死锁)
- 加锁时限(线程获取锁时加上时限,超时则放弃并释放所占有的锁,就能避免死锁)
- 死锁检测(一个更优的预防机制,主要针对不可能实现按序加锁和加锁时限的场景)
每当一个线程获得了锁,便在相关的数据结构中(Map
、Graph
等)将其记下。当一个线程请求锁失败时,这个线程可以遍历锁的关系图看看是否有死锁发生。
检测出死锁时,有一种解决方案是给这些线程设置优先级,让一个或多个线程回退,剩下的线程继续保持它们需要的锁。
对线程安全的理解
- 线程安全就是多线程访问时采用加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用。不会出现数据不一致或者数据污染
- 线程不安全就是不提供数据访问保护,有可能出现多个线程先后更改数据造成所得到的数据是脏数据
ThreadPoolExecutor
(构造函数参数)
int corePoolSize
:该线程池中核心线程数最大值int maximumPoolSize
: 该线程池中线程总数最大值long keepAliveTime
:该线程池中非核心线程闲置超时时长TimeUnit unit
:keepAliveTime
的单位BlockingQueue workQueue
:该线程池中的任务队列:维护着等待执行的Runnable
对象SynchronousQueue
:接收到任务时,会直接提交给线程处理,而不保留它LinkedBlockingQueue
:接收到任务时,如果当前线程数小于核心线程数,则新建核心线程处理任务;如果当前线程数等于核心线程数,则进入队列等待ArrayBlockingQueue
:接收到任务时,如果没有达到corePoolSize
的值,则新建核心线程执行任务;如果达到了,则入队等候;如果队列已满,则新建非核心线程执行任务;如果总线程数到了maximumPool
,且队列也满了,则发生错误DelayQueue
:接收到任务时,首先先入队,只有达到了指定的延时时间,才会执行任务。注意:队列内元素必须实现Delayed
接口,这就意味着你传进去的任务必须先实现Delayed接口
ConcurrentHashMap
(不了解)
ConcurrentHashMap
是Java并发包中提供的一个线程安全且高效的HashMap
实现,ConcurrentHashMap
采用了非常精妙的分段锁策略,ConcurrentHashMap
的主干是个Segment
数组。Segment
继承于ReentrantLock
,是一种可重入锁。在ConcurrentHashMap
中,一个Segment
就是一个子哈希表,Segment
里维护了一个HashEntry
数组,并发环境下,对于不同Segment
的数据进行操作不用考虑锁竞争。
HashMap和Hashtable
比较(没回答上来)
HashMap
:HashMap
基于散列表实现,其插入和查询<K,V>
的开销是固定的,可以通过构造器设置容量和负载因子来调整容器的性能。
HashMap
允许Key
和Value
为null
HashMap
是2倍扩容策略(oldThr << 1
)HashMap
是线程不安全的,在并发环境下,扩容时可能会形成环状链表,导致get
操作时cpu
空转。所以,在并发环境中使用HashMap
是非常危险的
Hashtable
:Hashtable
和HashMap
的实现原理几乎一样。
Hashtable
不允许Key
和Value
为null
Hashtable
是2倍+1扩容策略(newCapacity = (oldCapacity << 1) + 1
)Hashtable
是线程安全的。但是Hashtable
线程安全的策略实现代价很大,get/put
所有相关操作都是synchronized
的*,在竞争激烈的并发场景中性能非常差
HashMap
底层实现
- 底层实现:
HashMap
底层整体结构是一个数组,数组中的每个元素又是一个链表。每次添加一个对象(put
)时会产生一个链表对象(Object
类型),Map
中的每个Entry
就是数组中的一个元素(Map.Entry
就是一个<Key,Value>
),它具有由当前元素指向下一个元素的引用,这就构成了链表。 - 存储原理:当向
HsahMap
中添加元素的时候,先根据HashCode
重新计算Key
的Hash
值,得到数组下标,如果数组该位置已经存在其他元素,那么这个位置的元素将会以链表的形式存放,新加入的放在链头,最先加入的放在链尾,如果数组该位置元素不存在,那么就直接将该元素放到此数组中的该位置。
HashMap
Key
能否为null
,Value
能否为null
,null
的HashCode
能否计算(答错了)
HashMap
对象的Key
、Value
值均可为null
HahTable
对象的Key
、Value
值均不可为null
null
的HashCode
是0(o != null ? o.hashCode() : 0
)
MySQL
和Redis
比较
MySQL
:关系型数据库,数据放在磁盘Redis
:非关系型数据库,数据放在内存(使用RDB[快照
]方式或者AOF[日志
]方式持久化)。Redis
的优势包括速度、对富数据类型的支持(String
、Hash
、List
、Set
、Zset
)、原子性操作、通用性
合理的利用有限的内存,将读写频繁的热数据放在Redis
中才能更好感受到它带来的性能提升,要权衡内存开销和读写速度。
数据库索引
B-Tree
索引Hash
索引- 检索效率非常高
- 仅能满足
=
、IN
、<=>
查询,不能使用范围查询 - 只有
Memory
存储引擎显示支持Hash
索引
FullText
索引R-Tree
索引
平衡二叉树
它是一棵空树或它左右子树的高度差绝对值不超过1,且其左右子树都是平衡二叉树。
平衡二叉树必定是二叉搜索树,反之则不一定。平衡二叉树的常用实现方法有红黑树、AVL、替罪羊树、Treap、伸展树等。
B+树
B+ 树是一种树数据结构,是一个N叉排序树,每个节点通常有多个孩子,一棵B+树包含根节点、内部节点和叶子节点。根节点可能是一个叶子节点,也可能是一个包含两个或两个以上孩子节点的节点。
快速排序和堆排序算法及时间复杂度(堆排序忘了)
- 快速排序:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。时间复杂度O(nlogn) ,待排序的序列为正序或者逆序,时间复杂度O(n^2)
- 堆排序:堆分为最大堆和最小堆,其实就是完全二叉树。最大堆要求节点的元素都要不小于其孩子,最小堆要求节点元素都不大于其左右孩子,即处于最大/小堆的根节点的元素一定是这个堆中的最大/小值。堆排序算法就是抓住了堆的这一特点,每次都取堆顶的元素,将其放在序列最后面,然后将剩余的元素重新调整为最大堆,依次类推,最终得到排序的序列。时间复杂度O(nlogn)
对面向对象的理解(答得不好)
面向对象是一种对现实世界理解和抽象的方法。起初,面向对象专指在程序设计中采用封装、继承、多态等设计方法,后来面向对象的思想涉及到软件开发的各个方面。
- 面向对象分析是根据抽象关键的问题域来分解系统
- 面向对象设计是一种提供符号设计系统的面向对象的实现过程,它用非常接近实际领域术语的方法把系统构造成现实世界的对象
- 面向对象编程是一种在程序中包含各种独立而又互相调用的对象的思想
对多态的理解
在面向对象语言中,接口的多种不同的实现方式即为多态。
消息队列的使用(RabbitMQ
、ActiveMQ
)
- 主要特点是异步处理
- 主要目的是减少请求响应时间、解耦
- 主要使用场景是将比较耗时而且不需要即时(同步)返回结果的操作当做消息存入队列
消息队列中间件是分布式系统中重要的组件,主要解决应用耦合、异步消息、流量削锋等问题,实现高性能、高可用、可伸缩和最终一致性架构,是大型分布式系统不可缺少的中间件。具有异步性、可靠性(存储到本地硬盘)、松耦合、分布式的特性。
对分布式的理解(了解不深)
- 分布式:一个业务分拆多个子业务,部署在不同的服务器上(厨师和配菜师的关系)
- 集群:同一个业务,部署在多个服务器上(两个厨师的关系)
对微服务的理解(了解不深)
微服务架构风格是一种使用一套小服务来开发单个应用的方式,每个服务运行在自己的进程中,并使用轻量级机制通信(通常是HTTP API
),这些服务能够通过自动化部署机制来独立部署、可以使用不同的编程语言实现、可以使用不同的数据存储技术,并保持最低限度的集中式管理。
时下热门的微服务开发框架有:Spring Cloud、Dubbo
有没有发表过论文,有没有竞赛奖项
开发过程中遇到的难题以及解决方案
通过什么方式学习新的知识和技术
有什么想问的
转载:https://blog.csdn.net/u012102104/article/details/79502468