-
自我介绍
-
Java中Synchronized是怎么实现?
Synchronized修饰方法时:修饰普通方法锁的是当前的实例,修饰静态方法锁的是这个类。当方法调用时,调用指令将会检查该方法是否被设置acc_synchronized访问标志:flags:acc_public 和 acc_synchronized。
当synchronized修饰代码块的时候,锁的的是括号里面的对象。这种情况是用monitor和monitorexit指令来实现同步的,进入monitorenter指令后,线程将持有Monitor对象,退出moinorenter指令后,线程将释放该Monitor对象。 -
Synchronized修饰普通方法,代码块,静态方法都是锁的那些对象。
-
Java对象头里面都有什么
一个对象的内存结构包括:运行时元数据、类型指针、数据类型、对齐填充。
运行时元数据主要是包括:哈希值,gc分带年龄,锁状态标志等。
类型指针:是对方法区中类元信息的引用。
实例数据:真实记录一个对象包含的数据,比如说一个person对象,里面可能包含年龄、性别、身高等等,其中数据为字符串的,要引用到字符串常量池。
对齐填充:填充部分仅起到占位符的作用, 原因是HotSpot要求对象起始地址必须是8字节的整数,假如不是,就采用对齐填充的方式将其补齐8字节整数倍,那么为什么是8呢?原因是64位机器能被8整除的效率是最高的。 -
Java锁升级的过程?
锁升级过程主要依赖于对象头的Mark Word中锁的标志位和释放偏向锁标志位。Synchronized锁就是从偏向锁开始的,随着竞争的激烈偏向锁升级到轻量级锁最终升级到重量级锁。
- 偏向锁主要是为了用来优化同一线程多次申请同一个锁的竞争。当一个线程再次访问这个同步代码或方法时,该线程只需去对象头的 Mark Word 中去判断一下是否有偏向锁指向它的(线程) ID,无需再进入 Monitor 去竞争对象了。一旦出现其它线程竞争锁资源时,偏向锁就会被撤销。
- 轻量级锁:当有另外一个线程竞争获取这个锁时,发现对象头 Mark Word 中的线程 ID 不是自己的线程 ID,就会进行 CAS 操作获取锁。获取成功,直接替换Mark Word 中的线程 ID 为自己的 ID,该锁会保持偏向锁状态;如果获取锁失败,代表当前锁有一定的竞争,偏向锁将升级为轻量级锁。轻量级锁适用于线程交替执行同步块的场景,绝大部分的锁在整个同步周期内都不存在长时间的竞争。
- 自旋锁:通过自旋方式不断尝试获取锁,从而避免线程被挂起阻塞。在锁竞争不激烈且锁占用时间非常短的场景下,自旋锁可以提高系统性能。一旦锁竞争激烈或锁占用的时间过长,自旋锁将会导致大量的线程一直处于 CAS 重试状态,占用 CPU 资源,反而会增加系统性能开销。
- 重量级锁:自旋锁重试之后如果抢锁依然失败,同步锁就会升级至重量级锁。
-
Java中中断和异常的区别?恢复现场的流程。
-
线程池的主要参数
ThreadPoolExecutor的主要参数
corePoolSize (线程池基本大小)
maximumPoolSize(线程池最大大小)
keepAliveTime(线程存活保持时间)
workQueue(任务队列):用于传输和保存等待执行任务的阻塞队列
threadFactory(线程工厂):用于创建新线程。threadFactory创建的线程也是采用new Thread()方式,threadFactory创建的线程名都具有统一的风格:pool-m-thread-n(m为线程池的编号,n为线程池内的线程编号)。
handler(线程饱和策略):当线程池和队列都满了,再加入线程会执行此策略。 -
spring aop和IOC的实现原理。
Spring aop
概念:那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性。
在spring中主要是基于动态代理来做的,有以下两种实现方式:
- 基于jdk的proxy进行代理
- 基于cglib的字节码增强的方式
Spring IOC
IOC(控制反转,别名也叫依赖注入)就是依赖倒置原则的一种代码设计思路。就是把原先在代码里面需要实现的对象创建、对象之间的依赖,反转给容器来帮忙实现。
Spring IOC容器通过xml,注解等其它方式配置类及类之间的依赖关系,然后通过反射机制完成了对象的创建和依赖的管理注入。
- springMVC的执行流程
1.Tomcat在启动时加载解析web.xml,找到spring mvc的前端总控制器DispatcherServlet,并且通过DispatcherServlet来加载相关的配置文件信息。
2.DispatcherServlet接收到客户端请求,找到对应HandlerMapping,根据映射规则,找到对应的处理器方法。
3.调用相应处理器中的处理方法,处理该请求后,会返回一个ModelAndView对象。
4.DispatcherServlet根据得到的ModelAndView中的视图对象,找到一个合适的ViewResolver(视图解析器),根据视图解析器的配置,DispatcherServlet将要显示的数据传给对应的视图,最后显示给用户。
-
MySQL的索引数据结构?B和B+树的区别?
-
Mysql 聚簇索引和非聚簇索引的区别?
-
给一个数组,在里面找到任意一个波峰。返回其索引
public class FindPeak {
public static void main(String[] args) {
int[] nums = {1,3,2,4,5,6};
System.out.println(findcrest(nums));
}
/**
* 随机寻找一个波峰
* @param nums
* @return
*/
public static int findcrest(int[] nums){
int left=0;
int right = nums.length-1;
int n = nums.length;
while (left <= right){
int mid = (left + right) /2;
if(mid ==0){
left =1;
continue;
}
if(mid == n-1){
right = n-2;
continue;
}
if(nums[mid] >nums[mid-1] && nums[mid] > nums[mid+1]){
return mid;
}else if(nums[mid] < nums[mid-1]){
right = mid -1;
}else {
left = mid+1;
}
}
return -1;
}
}