小言_互联网的博客

阿里Java实习面试

259人阅读  评论(0)

  2018年3月9日16时08分接到阿里Java实习生电话面试,进行了48分钟,记录如下:


自我介绍

多线程几种实现方式

  1. 继承Thread类创建线程
  2. 实现Callable接口创建线程
  3. 实现Runnable接口创建新线程

进程和线程的状态

  • 进程:创建、就绪、执行、阻塞、终止
  • 线程:就绪、执行、阻塞

synchronizedLock

  1. synchronized是一种同步锁,可用于修饰方法、对象、类、代码块,是关键字。而Lock是一个接口
  2. synchronized是隐式锁,在需要同步的对象中加入此控制,而Lock是显示锁,需要显示指定起始位置和终止位置
  3. 使用Lock时在finally中必须释放锁,不然容易造成线程死锁;而使用synchronized时,获取锁的线程会在执行完同步代码后释放锁(或者JVM会在线程执行发生异常时释放锁)
  4. 使用Lock时线程不会一直等待;而使用synchronized时,假设A线程获得锁后阻塞,其他线程会一直等待
  5. Lock可重入、可中断、可公平也可不公平;而synchronized可重入但不可中断、非公平

锁的类型

  • 可重入锁(synchronizedReentrantLock都是可重入锁)
  • 可中断锁(synchronized就不是可中断锁,而Lock是可中断锁)
  • 公平锁(以请求锁的顺序来获取锁)
  • 读写锁(ReadWriteLock就是读写锁,ReentrantReadWriteLock实现了这个接口)

死锁避免

  • 加锁顺序(线程按一定顺序加锁,若所有线程都按相同顺序获得锁,就能避免死锁)
  • 加锁时限(线程获取锁时加上时限,超时则放弃并释放所占有的锁,就能避免死锁)
  • 死锁检测(一个更优的预防机制,主要针对不可能实现按序加锁和加锁时限的场景)

  每当一个线程获得了锁,便在相关的数据结构中(MapGraph等)将其记下。当一个线程请求锁失败时,这个线程可以遍历锁的关系图看看是否有死锁发生。

  检测出死锁时,有一种解决方案是给这些线程设置优先级,让一个或多个线程回退,剩下的线程继续保持它们需要的锁。

对线程安全的理解

  • 线程安全就是多线程访问时采用加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用。不会出现数据不一致或者数据污染
  • 线程不安全就是不提供数据访问保护,有可能出现多个线程先后更改数据造成所得到的数据是脏数据

ThreadPoolExecutor(构造函数参数)

  1. int corePoolSize:该线程池中核心线程数最大值
  2. int maximumPoolSize: 该线程池中线程总数最大值
  3. long keepAliveTime:该线程池中非核心线程闲置超时时长
  4. TimeUnit unitkeepAliveTime的单位
  5. 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比较(没回答上来)

  • HashMapHashMap基于散列表实现,其插入和查询<K,V>的开销是固定的,可以通过构造器设置容量和负载因子来调整容器的性能。
  1. HashMap允许KeyValuenull
  2. HashMap是2倍扩容策略(oldThr << 1
  3. HashMap是线程不安全的,在并发环境下,扩容时可能会形成环状链表,导致get操作时cpu空转。所以,在并发环境中使用HashMap是非常危险的
  • HashtableHashtableHashMap的实现原理几乎一样。
  1. Hashtable不允许KeyValuenull
  2. Hashtable是2倍+1扩容策略(newCapacity = (oldCapacity << 1) + 1
  3. Hashtable是线程安全的。但是Hashtable线程安全的策略实现代价很大,get/put所有相关操作都是synchronized的*,在竞争激烈的并发场景中性能非常差

HashMap底层实现

  • 底层实现:HashMap底层整体结构是一个数组,数组中的每个元素又是一个链表。每次添加一个对象(put)时会产生一个链表对象(Object类型),Map中的每个Entry就是数组中的一个元素(Map.Entry就是一个<Key,Value>),它具有由当前元素指向下一个元素的引用,这就构成了链表。
  • 存储原理:当向HsahMap中添加元素的时候,先根据HashCode重新计算KeyHash值,得到数组下标,如果数组该位置已经存在其他元素,那么这个位置的元素将会以链表的形式存放,新加入的放在链头,最先加入的放在链尾,如果数组该位置元素不存在,那么就直接将该元素放到此数组中的该位置。

HashMap Key能否为nullValue能否为nullnullHashCode能否计算(答错了)

  • HashMap对象的KeyValue值均null
  • HahTable对象的KeyValue值均不可null
  • nullHashCode是0(o != null ? o.hashCode() : 0

MySQLRedis比较

  • MySQL:关系型数据库,数据放在磁盘
  • Redis:非关系型数据库,数据放在内存(使用RDB[快照]方式或者AOF[日志]方式持久化)。Redis的优势包括速度、对富数据类型的支持(StringHashListSetZset)、原子性操作、通用性

  合理的利用有限的内存,将读写频繁的热数据放在Redis中才能更好感受到它带来的性能提升,要权衡内存开销和读写速度。

数据库索引

  • B-Tree索引
  • Hash索引
    • 检索效率非常高
    • 仅能满足=IN<=>查询,不能使用范围查询
    • 只有Memory存储引擎显示支持Hash索引
  • FullText索引
  • R-Tree索引

平衡二叉树

  它是一棵空树或它左右子树的高度差绝对值不超过1,且其左右子树都是平衡二叉树。

  平衡二叉树必定是二叉搜索树,反之则不一定。平衡二叉树的常用实现方法有红黑树、AVL、替罪羊树、Treap、伸展树等。

B+树

  B+ 树是一种树数据结构,是一个N叉排序树,每个节点通常有多个孩子,一棵B+树包含根节点、内部节点和叶子节点。根节点可能是一个叶子节点,也可能是一个包含两个或两个以上孩子节点的节点。

快速排序和堆排序算法及时间复杂度(堆排序忘了)

  • 快速排序:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。时间复杂度O(nlogn) ,待排序的序列为正序或者逆序,时间复杂度O(n^2)
  • 堆排序:堆分为最大堆和最小堆,其实就是完全二叉树。最大堆要求节点的元素都要不小于其孩子,最小堆要求节点元素都不大于其左右孩子,即处于最大/小堆的根节点的元素一定是这个堆中的最大/小值。堆排序算法就是抓住了堆的这一特点,每次都取堆顶的元素,将其放在序列最后面,然后将剩余的元素重新调整为最大堆,依次类推,最终得到排序的序列。时间复杂度O(nlogn)

对面向对象的理解(答得不好)

  面向对象是一种对现实世界理解和抽象的方法。起初,面向对象专指在程序设计中采用封装、继承、多态等设计方法,后来面向对象的思想涉及到软件开发的各个方面。

  1. 面向对象分析是根据抽象关键的问题域来分解系统
  2. 面向对象设计是一种提供符号设计系统的面向对象的实现过程,它用非常接近实际领域术语的方法把系统构造成现实世界的对象
  3. 面向对象编程是一种在程序中包含各种独立而又互相调用的对象的思想

对多态的理解

  在面向对象语言中,接口的多种不同的实现方式即为多态。

消息队列的使用(RabbitMQActiveMQ

  1. 主要特点是异步处理
  2. 主要目的是减少请求响应时间、解耦
  3. 主要使用场景是将比较耗时而且不需要即时(同步)返回结果的操作当做消息存入队列

  消息队列中间件是分布式系统中重要的组件,主要解决应用耦合、异步消息、流量削锋等问题,实现高性能、高可用、可伸缩和最终一致性架构,是大型分布式系统不可缺少的中间件。具有异步性、可靠性(存储到本地硬盘)、松耦合、分布式的特性。

对分布式的理解(了解不深)

  • 分布式:一个业务分拆多个子业务,部署在不同的服务器上(厨师和配菜师的关系)
  • 集群:同一个业务,部署在多个服务器上(两个厨师的关系)

对微服务的理解(了解不深)

  微服务架构风格是一种使用一套小服务来开发单个应用的方式,每个服务运行在自己的进程中,并使用轻量级机制通信(通常是HTTP API),这些服务能够通过自动化部署机制来独立部署、可以使用不同的编程语言实现、可以使用不同的数据存储技术,并保持最低限度的集中式管理。

  时下热门的微服务开发框架有:Spring CloudDubbo

有没有发表过论文,有没有竞赛奖项

开发过程中遇到的难题以及解决方案

通过什么方式学习新的知识和技术

有什么想问的


转载:https://blog.csdn.net/u012102104/article/details/79502468
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场