一面
-
Spring源码有什么可借鉴之处?Spring bean的生命周期?Spring容器近似是个什么数据结构?A:Spring容器是一个Map类型的数据结构,其中key是Bean的名称,value是Bean的实例。
-
索引优化应该从哪些方面考虑?Answer by newBing:
首先应考虑在 where 及 order by涉及的列上建立索引;
应尽量避免在 where 子句中使用 !=或<> 操作符,否则将引擎放弃使用索引而进行全表扫描;
索引长度以及区分度;
联合索引需要考虑索引先后顺序(最左前缀匹配);
索引覆盖是指,如果查询的列恰好是索引的一部分,那么查询只需要在索引文件上进行,不需要回行到磁盘再找数据(即避免回表)。 -
Reentrantlock公平锁、非公平锁。相关知识:本博----一些AQS相关的知识
-
为什么不同的隔离级别读到的数据不一样?了解MySQL MVCC的Read View吗?相关知识可参考本博----《高性能Mysql 第三版》笔记中MVCC的部分
-
数据库如何回滚?A:undo log. Q: 如果你来设计undo log,你怎么做? 参考上个回答中的内容
-
kafka的消息,是按什么算法,决定它被分配到哪个partition的?参考答案1,2:
If a partition is specified in the record, use it 指定了partition,则消息投递到指定的partition
If no partition is specified but a key is present choose a partition based on a hash of the key 未指定partition,但指定了key, 则基于hash(key)取模选择一个分区
If no partition or key is present choose a partition in a round-robin fashion 分区编号和key均未指定,则轮询选择,round-robin
二面
- 两个线程同时对HashMap进行写操作,会有什么线程安全的问题吗?举例说明。后面在聊ConcurrentHashMap在JDK1.8之后锁的变化,我聊到锁粒度变小,面试官问有没有粒度变大的情形,比如扩容时?结合3等文和面试官最后的总结来看,应该是没有
- synchronized锁升级过程。Q:锁升级的意义?为什么没有锁降级?相关知识:我还是倾向于认为没有锁降级,从https://segmentfault.com/q/1010000020803904来看有过锁降级的提案 JEP draft: Concurrent Monitor Deflation,但是似乎被否了。
- Monitor。相关知识4:
通俗来说就是调用了wait()方法的线程就会进入waitset。(下图来自 https://www.artima.com/insidejvm/ed2/threadsynch.html,有时间可看看)。但是对比了JavaGuide pdf中的《Java 线程状态变迁图》后,感觉下图有点小问题,wait set中的线程被notify/notifyAll唤醒后,不一定能抢到锁,如果没有就应该进入此图中的Entry Set:
注:OS线程中的Running、Ready两状态都对应于Java线程中的Runnable状态。
5这里提个会使人困惑的问题: 使用socket时,调用accept(),read() 等阻塞方法时,线程处于什么状态?
答案是java线程处于RUNNABLE状态,OS线程处于WAITING状态。因为在jvm层面,等待cpu时间片和等待io资源是等价的。
扩展与类比:接口java.util.concurrent.locks.Condition
的注释:
Condition factors out the Object monitor methods (wait, notify and notifyAll) into distinct objects to give the effect of having multiple wait-sets per object, by combining them with the use of arbitrary Lock implementations.Where a Lock replaces the use of synchronized methodsand statements, a Condition replaces the use of the Object monitor methods.
- AQS的原理?除了CLH同步队列,没有其它队列吗?参考答案6:条件队列。更准确点应该是Lock的Condition会有条件队列。
类AbstractQueuedSynchronizer里的static final class Node是CLH同步队列的结点类,从下面Node类的一段注释,以及AQS里用到的ConditionObject类的代码都可以看出,它同时也是条件队列的结点类:
Threads waiting on Conditions use the same nodes, but use an additional link. Conditions only need to link nodes in simple (non-concurrent) linked queues because they are only accessed when exclusively held. Upon await, a node is inserted into a condition queue. Upon signal, the node is transferred to the main queue. A special value of status field is used to mark which queue a node is on.
public class ConditionObject implements Condition, java.io.Serializable {
...
/** First node of condition queue. */
private transient Node firstWaiter;
/** Last node of condition queue. */
private transient Node lastWaiter;
...
/**
* Adds a new waiter to wait queue.
* @return its new wait node
*/
private Node addConditionWaiter() {
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
Node t = lastWaiter;
// If lastWaiter is cancelled, clean out.
if (t != null && t.waitStatus != Node.CONDITION) {
unlinkCancelledWaiters();
t = lastWaiter;
}
Node node = new Node(Node.CONDITION);
if (t == null)
firstWaiter = node;
else
t.nextWaiter = node;
lastWaiter = node;
return node;
}
...
public final void await() throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
Node node = addConditionWaiter();
...
}
Condition的条件队列像极了Monitor的Wait Set。区别是Condition更灵活,因为一个Lock可以有多个Condition,也就可以有多条条件队列,但是一个Monitor有且只有一个Wait Set。唯一的疑惑是Condition.await方法是否会删除同步队列里的头节点。从代码和注释里我没有找到删除的证据,但是我倾向于删了,因为这动作事实上会造成该线程阻塞,似乎不应该再留它当头节点。而且上段引用中提到:A special value of status field is used to mark which queue a node is on,而static final int CONDITION
的注释为 /** waitStatus value to indicate thread is waiting on condition. */
-
- BlockingQueue的offer方法,底层如何实现的?相关知识:ArrayBlockingQueue的源码:一个Lock及它的两个Condition:
final ReentrantLock lock;
/** Condition for waiting takes */
private final Condition notEmpty;
/** Condition for waiting puts */
private final Condition notFull;
...
public ArrayBlockingQueue(int capacity, boolean fair) {
if (capacity <= 0)
throw new IllegalArgumentException();
this.items = new Object[capacity];
lock = new ReentrantLock(fair);
notEmpty = lock.newCondition();
notFull = lock.newCondition();
}
-
- 线程池应该用ArrayBlockingQueue还是LinkedBlockingQueue好?相关知识:LinkedBlockingQueue相对于ArrayBlockingQueue来说,具有更高的吞吐量,因为它实现了更加细粒度的锁操作。LinkedBlockingQueue中的锁是分离的,即生产用的是putLock,消费用的是takeLock。这样可以在高并发情况下减少锁竞争,提高吞吐量。LinkedBlockingQueue缺点在于没有限定长度,有内存溢出风险
-
一个接口响应慢,可能是哪些原因?网络延迟、数据库负载过高、代码问题、缓存失效、第三方服务故障、被限速等.
-
有遇到过MQ消息堆积的情况吗