tcp三次握手,四次挥手。time-wait、close-wait状态。MSL代表什么?为什么time-wait是2MSL,可不可以更长?如果不设置time-wait有什么影响
TCP如何保证可靠性传输?ARQ重传什么时候会重传?超时计时器时间如何设置?(其实就是问拥塞控制)?TCP如何进行快速重传
HTTP为什么是无状态协议?Cookie和Session?Session保存在哪里?Session共享?
如何判断对象是否死亡?引用计数器有什么缺点?可达性分析算法能否解决A引用B,B引用A的情况(循环引用)?什么适合做GC Roots?
使用引用计数器,若出现A引用B,B引用A的情景,A、B对象永远不会被回收。
使用可达性分析算法,若出现A引用B,B引用A的情景,C是可达的,此时AB间存在关系,但是是不可达的。可以回收
适合做GC Roots的对象(两栈两方法)
强引用、弱引用、软引用、虚引用?
ThreadLocal?
线程的生命周期?(Block、Time waiting状态的区别)
可重入锁和不可重入锁的区别?synchronized是可重入锁?一个线程是否可以重复获取一个锁?
不可重入锁:同一个线程只能获取一次该资源的锁
public class Lock{
private boolean isLocked = false;
public synchronized void lock() throws InterruptedException{
//不可重入锁只用判断当前锁的状态,如果是true表示锁已被获取,就进入WAITING态
while(isLocked){
wait();
}
isLocked = true;
}
//不可重入锁解锁只用将标记设置为false,然后通知其它WAITING线程
public synchronized void unlock(){
isLocked = false;
notify();
}
}
可重入锁:同一个线程可以多次获取同一个资源的锁。可重入强调对单个线程执行时重新进入同一个子程序仍然是安全的。
public class Lock{
boolean isLocked = false;
Thread lockedBy = null;
int lockedCount = 0;
public synchronized void lock()
throws InterruptedException{
Thread thread = Thread.currentThread();
//可重入锁还要判断当前申请锁的线程是否是拥有锁的线程,如果不是,进入WAITING态,保证该资源的互斥条件
while(isLocked && lockedBy != thread){
wait();
}
//如果 获取锁的线程就是当前申请锁的线程,该线程在此获取该资源的锁,计数器++
isLocked = true;
lockedCount++;
lockedBy = thread;
}
//可重入锁解锁:只有当前线程是拥有锁的线程,让锁计数器--,如果锁计数器为0表示锁没有被任何线程占有,将其状态更新并通知其它WAITING线程
public synchronized void unlock(){
if(Thread.currentThread() == this.lockedBy){
lockedCount--;
if(lockedCount == 0){
isLocked = false;
notify();
}
}
}
}
如调用A方法需要获取资源1的锁,A中调用B方法,B中也要获取资源1的锁。若是不可重入锁,会发生死锁;若是可重入锁,A、B方法是同一个线程调用,该线程获取重复获取资源1的锁,会判断申请该锁的线程是否是拥有该锁的线程,如果是,可以获取锁,LockCount++。可重入强调对单个线程执行时重新进入同一个子程序仍然是安全的。
public class Test{
Lock lock = new Lock();
public void methodA(){
lock.lock();
...........;
methodB();
...........;
lock.unlock();
}
public void methodB(){
lock.lock();
...........;
lock.unlock();
}
}
synchronized是可重入锁(递归锁)。即synchronized方法递归调用不会发生死锁,说明其是可重入锁
public class Main{
public static void main(String[] args) throws CloneNotSupportedException {
Main m = new Main();
m.main1();
}
public synchronized void main1(){
System.out.println("main1 exec...");
main2();
}
private synchronized void main2() {
System.out.println("main2 exec...");
main3();
}
private synchronized void main3() {
System.out.println("main3 exec...");
}
}
//不会死锁,说明synchronized是可重入锁
main1 exec...
main2 exec...
main3 exec...
悲观锁和乐观锁?CAS?ABA问题如何解决?
线程池的7个参数?饱和策略?线程池原理?是否可以先创建线程再添加到工作队列中?
- 不可以先创建线程,再加入队列。这是因为创建线程所需资源比加入队列要大。从系统开销思考。
重量级锁是否一定比轻量级锁耗费资源?
MySQL索引的数据结构?b+索引的时间复杂度?
事务并发存在的问题?事务的隔离级别?
当前读和快照读的区别?MVCC是如何实现读已提交和可重复读的?
组合索引?select * from T where a = 1 and b < 10 and c = 2;走那些索引?
index(a,b,c)
where a=3 只使用了a
where a=3 and b=5 使用了a,b
where a=3 and b=5 and c=4 使用了a,b,c
where b=3 or where c=4 没有使用索引
where a=3 and c=4 仅使用了a
where a=3 and b>10 and c=7 使用了a,b。这是因为走a索引后,查出来的b是有序的,b也会走索引,而b是范围查找,查出来的c是无序的不走索引
where a=3 and b like 'xx%' and c=7 使用了a,b
场景:在海量数据中如何精确匹配到某个值?
如何在1万个数据中找到最大的top999?
- 堆排序,堆中元素只有100个,建小顶堆,堆顶元素最小,每来一个值与顶堆元素比较,如果比他小,那么肯定是top999里的。
- 求最大topK建小顶堆,反之,求最小topK建大顶堆
- 堆中元素个数为K
- 如在1万个数据中找到最大的top999,从10000个数中任取999个建小顶堆,此时堆顶元素是最小的。然后遍历10000个数剩余元素,每一个元素与堆顶元素进行比较,若比堆顶元素大,将堆顶元素置为该值`arr[0] = nums[k]`,然后`heapify(arr, n, 0),此时的结果是将可能是top999中的数放到堆中`;若比堆顶元素小,遍历下一个元素,直到nums遍历结束。此时堆中元素就是topK
算法:连续子数组的最大和
反问:工作业务与技术栈