JAVA面试点2

CREATED: 2021-02-28 15:00

production 生产环境

devops 运维开发

 

https://www.bilibili.com/video/BV1AZ4y1379A?p=2&spm_id_from=pageDriver

CPU从内存里面读取指令和数据

工作线程数是不是设置的越大越好?不是 线程切换会有一定的开销

工作线程数设置多少合适?Ncpu * Ucpu * (1 + W/C) = 处理器核的数目 * 期望cpu利用率 * (1 + 等待时间/计算时间比率)

W/C 根据压测来预估推算

 

线程撕裂者:一个计算单元对应多个可以保存线程的寄存器 节省线程切换时间

 

ThreadLocal 线程本地变量

线程本地缓存 L1 L2 L3 在cpu中,先去L1, 再去L2,L3,如果都没有最后去内存读。

 

缓存行:一次性读的一块的数据,64Bytes。同一航数据被不同cpu缓存,需要同步机制:缓存一致性协议。MESI

前后都有7个无意义的long类型数据:保证不与其它要修改数据在同一缓存行。

 

并发编程三大特性

1. 可见性

2. 有序性: 程序可以乱序执行,保证单线程最终一致性。

3. 原子性

 synchronized: 保证线程可见性,把CPU缓存内容刷到内存中。

 

2021/03/16

僵尸进程

一个进程结束自己的时候,其实它并没有真正的被销毁,因为它的父进程没安装SIGCHLD信号处理函数调用wait或waitpid等待子进程结束,其保留的那段信息就不会释放,其进程号就会一直被占用。

任何一个子进程(init除外)在exit()之后,并非马上就消失掉,而是留下一个称为僵尸进程(Zombie)的数据结构,等待父进程处理。这是每个子进程在结束时都要经过的阶段。如果子进程在exit()之后,父进程没有来得及处理,这时用ps命令就能看到子进程的状态是“Z”。

解决办法:杀死僵尸进程的父进程(僵尸进程的父进程必然存在),僵尸进程成为"孤儿进程",过继给1号进程init,init始终会负责清理僵尸进程。

 

线程死锁

线程死锁的原因

1 互斥条件:指进程对所分配到的资源进行排它性使用,即在一段时间内某资源只由一个进程占用。如果此时还有其它进程请求该资源,则请求者只能等待,直至占有该资源的进程用毕释放。
2 请求与保持条件:指进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源又被其它进程占有,此时请求进程阻塞,但又对自己获得的其它资源保持不放。
3 不剥夺条件:指进程已获得资源,在使用完之前,不能被剥夺,只能在使用完时由自己释放。
4 环路等待条件:指在发生死锁时,必然存在一个进程—资源的环形链,即进程集合(P0,P1,P2,…,Pn)中的P0正在等待一个P1占用的资源;P1正在等待一个P2占用的资源,……,Pn正在等待已被P0占用的资源。

解决方法

破坏互斥条件:无法做到

破坏请求与保持条件 : 一次性申请所有的资源。

破坏不剥夺条件: 占用部分资源的线程进一步申请其他资源时,如果申请不到,可以主动释放它占有的资源。

破坏循环等待条件: 靠按序申请资源来预防。按某一顺序申请资源,释放资源则反序释放。破坏循环等待条件。

 

2021/04/17

Thread中的run和start

调用start方法方可启动新线程,而run方法只是thread的一个普通方法调用,还是在主线程里执行。

start() 实现了多线程,run()没有实现多线程。

 

启动线程的三种方式

1 继承Thread

2 实现Runnable

3 通过线程池来启用 Executors

 

sleep join yield  wait

1.sleep:Thread类的方法,必须带一个时间参数。会让当前线程休眠进入阻塞状态并释放CPU,但不释放锁资源。

2.yield:Thread类的方法,让出CPU调度,类似sleep只是不能由用户指定暂停多长时间 ,并且yield()方法只能让同优先级的线程有执行的机会。 yield()只是使当前线程重新回到可执行状态,所以执行yield()的线程有可能在进入到可执行状态后马上又被执行。 

3.join:当前运行线程调用另一个线程的join方法,当前线程进入阻塞状态直到另一个线程运行结束。

4.wait():让出CPU资源和锁资源。Object类的方法(notify()、notifyAll()  也是Object对象),必须放在循环体和同步代码块中,执行该方法的线程会释放锁,进入线程等待池中等待被再次唤醒。

 

synchronized

可重入锁

object:不能用String常量,Integer, Long

锁升级:偏向锁,自旋锁,重量级锁(向操作系统申请)。

自旋锁 : 占cpu 但不访问操作系统,仅用户态,不经过内核态。适合执行时间短,线程数目少的情况。

 

volatile

1 保证线程可见性MESI 缓存一致性协议

2 禁止指令重排序

但是不能保证原子性

 

CAS

Compare And Set 比较并设置 

cas(V, ExpectedValue, NewValue) 

if V == E then V = New;

else retry or fail;

CPU原语支持

AtomicStampedReference 版本号解决ABA问题 - object问题

 

2021/07/21

try catch finally 中遇到的return问题

不管有没有出现异常,finally块中代码都会执行;当try和catch中有return时,finally仍然会执行。

如果有finally代码块,不管有没有异常,finally中的代码都会执行。当try、catch中有return时并没有返回运算之后的值,而是把值保存起来,继续执行finally中的代码,不管finally中对该值有没有做改变,返回的值都不会改变,依然返回保存起来的值。finally代码中最好不要包含return,程序会提前退出,也就是说返回的值不是try或catch中的值。finally中有return语句则直接返回退出,无法执行后面的语句。

finally里的语句只有两种情况下,会不被执行。一种是,在try-catch语句之前,程序就结束了或者挂掉了。第二种是遇到System.exit();

source - https://cloud.tencent.com/developer/article/1694051

 

堆内存:年轻代+老年代,统称为堆,可设置大小

年轻代分为三块:年轻代(eden区)、S1区、S2区(survivor区),默认情况下,新生代:S1:S2比例是8:1:1。



B+树和B树区别

B树的非叶子节点存储实际记录的指针,而B+树的叶子节点存储实际记录的指针

B+树的叶子节点通过指针连起来了, 适合扫描区间和顺序查找。

 

2021/08/03

@SneakyThrows

作用于方法上,相当于把方法内的代码添加了一个try-catch处理,捕获异常catch中用Lombok.sneakyThrow(e)抛出异常。使用@SneakyThrows(XXXException.class)指定抛出具体异常。

public void run() {
    try {
      throw new Throwable();
    } catch (Throwable t) {
      throw Lombok.sneakyThrow(t);
    }
}


posted @ 2021-03-01 09:56  YBgnAW  阅读(65)  评论(0)    收藏  举报