- 1. JDK、JRE、JVM的区别和联系
- 2. ==与equals
- 3. final关键字的作用及为什么局部内部类和匿名内部类只能访问局部final变量?
- 4. String、StringBuild、StringBuffer
- 5. 重载和重写
- 6. 接口和抽象类的区别
- 7. Set与List的区别
- 8. hashCode与equals
- 9. ArrayList与linkedList区别
- 10. HashMap与HashTable的区别?底层实现是什么?
- 11. ConcurrentHashMap原理
- 12. Java类加载器
- 13. 双亲委派模型
- 14. Java中的异常体系
- 15. GC是如何判断对象是否可以被回收
- 16. 线程的生命周期,线程有哪些状态?
- 17. sleep()、wait()、join()、yield()的区别
- 18. 守护线程的理解
- 19. ThreadLocal的原理和使用场景
- 20. 并发的三大特性:
- 21. 为什么使用线程池?线程池的参数说明?
- 22. Redis中的击穿、穿透、雪崩?
- 23. Spring事务什么时候会失效?
- 24. SpringBoot 、Spring、SpringMVC有什么区别?
- 25. SpringMVC工作流程
JDK是java开发工具包,供java开发人员使用;
JRE:是Java运行时环境,用户想要运行java程序就需要有JRE
JVM是Java虚拟机,Java源代码编译成class文件后,由JVM解释为对应 *** 作系统的字节码。
JDK包含了JRE,JRE包含了JVM。
2. ==与equalsObject类中的equals实现就是用==,一般来说==对比的基本类型比较的是值,引用类型比较的是引用地址,String类重写了equals方法,
3. final关键字的作用及为什么局部内部类和匿名内部类只能访问局部final变量?final关键字可以修饰:
- 类:不可被继承
- 方法:不可被重写
- 变量:
- 值类型:不可修改
- 引用类型:引用地址不可变,但是引用内的值可以修改。
局部内部类或匿名内部类只能访问局部final变量的原因是内部类编译后实际上是单独的类文件,如果外部类调用完后被标记为垃圾,可能会被gc去回收,此时内部类调用局部变量如果不是final就存在问题了。
4. String、StringBuild、StringBufferString类被final修饰,表示不可变的最终类。StringBuffer和StringBuilder都是可变字符串,一般在不变的字符串中使用String,性能优先的情况下使用StringBuilder,在多线程中确保同步时使用StringBuffer
5. 重载和重写重载:两同(同一个类,方法名相同)、三不同(参数:类型、个数、顺序不同)与方法返回值和访问修饰符无关。
重写:有继承关系的父子类中,子类覆盖父类同名的方法,方法声明相同,实现不同。
总结:重载看参数,重写看方法实现
6. 接口和抽象类的区别抽象类中可以有普通方法,接口中都是抽象方法
只能继承一个抽象类,但是可以实现多个接口,接口之间可以有多继承。
抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是public static final 类型
从设计目的看,接口是一种规定类“有”什么的约束(like a);而抽象类的目的是代码的复用,当某些类有一些相同的行为时就可以派生出一个抽象类(is a)。
7. Set与List的区别List是有序,可重复的集合,按对象进入的顺序保存对象,允许有多个null,获取元素时可以用iterator取出元素再遍历,也可以用get下标的方式获取指定元素。
Set是无序不可重复的集合,最多有一个null,取元素时只能用iterator遍历获取。
都是Collection的子接口
8. hashCode与equals两个对象相等,则它们的hashCode值也是相同的;这两个对象分别调用equals方法返回的都是true。
但是如果两个hashCode值相同,这两个对象不一定相等。因此,equals方法被重写,则hashCode方法也要被重写。
9. ArrayList与linkedList区别ArrayList是动态数组实现的,使用连续的内存,适合用下标直接访问。扩容时会新建一个数组,把旧数组所有元素复制过来,这样比较消耗性能。一般如果在创建ArrayList集合时指定合适的初始大小,并采用尾部插入的方式效率会更高。
linkedList是链表实现,在内存中分散存储。需要用Iterator获取元素。
10. HashMap与HashTable的区别?底层实现是什么?区别:
HashMap是线程不安全的,HashTable是线程安全的(方法加了synchronized),如果保证多线程安全可以采用juc包下的ConcurrentHashMap;HashMap允许key和value为null,HashTable不允许。
HashMap底层实现: HashMap由数组+链表实现。
从jdk8开始,当链表高度达到8,数组长度达到64时,链表转变为红黑树,元素以内部类Node节点存在。
计算key的hash值,二次hash后对数组长度取模,对应到数组下标。
如果该下标没有值,那么直接将Node存入该位置。
如果有值,也就是产生了hash冲突,先进行equal比较,相同则取代该元素。不同的话就判断链表高度插入链表。链表高度达到8,数组长度达到64时,链表转变为红黑树,长度低于6时则红黑树转变为链表。
如果key为null,存在下标为0的位置。
数据结构:synchronized+CAS(乐观锁)+Node+红黑树,Node的val和next都使用了volatile修饰,保证可见性。查找、替换、赋值 *** 作都使用了CAS。
读 *** 作不加锁。
12. Java类加载器JDK自带的有三个类加载器:BootstrapClassLoader、ExtClassLoader、AppClassLoader
Bootstrap 默认负责加载 %JAVA_HOME%/lib下的jar包和class文件
ExtClassLoader负责加载%JAVA_HOME%/lib/ext文件夹下的jar包和class类
AppClassLoader负责加载classpath下的类文件
自定义类加载器
13. 双亲委派模型 14. Java中的异常体系- Throwable
- Exception
- RuntimeException 程序运行过程中
- CheckedException 程序编译过程中
- Error
- Exception
可达性分析法:从GC Roots开始向下搜索,搜索所走过的路径称为引用链。当一个对象到GCRoots没有任何引用链时,证明此对象是不可用的。那么虚拟机就判断是可回收对象。
GCRoots的对象有:
- 虚拟机栈(栈帧中的本地变量表)中引用的对象
- 方法区中类静态属性引用的对象
- 方法区中常量引用的对象
- 本地方法栈中JNI(Native)引用的对象。
线程状态:创建、就绪、执行、阻塞(等待阻塞、同步阻塞、其他阻塞如sleep等)、死亡
17. sleep()、wait()、join()、yield()的区别sleep()是Thread类的方法,wait()是Object类的方法,sleep()执行后不会释放锁,在到达时间后会直接处于就绪状态争夺CUP执行全,wait()会释放锁,需要被其他线程调用notify()或notifyAll()唤醒,唤醒后重写获取锁。
sleep()可以在任何地方使用,wait()只能配合synchronized使用
yield()执行后线程直接进入就绪状态,马上释放CUP执行权,但依然保留了争夺CUP的执行资格,可能下次CUP进行线程调度时还会让这个线程继续执行。
join()执行后线程进入阻塞状态,如:在主线程中A线程调用了join()方法,则主线程进入阻塞,直到A线程执行结束或中断线程,主线程才继续执行。
18. 守护线程的理解为所有非守护线程服务的线程,任何一个守护线程都是整个JVM中所有非守护线程的保姆。
注意:守护线程的终止是自身无法控制的,所以不要把IO、File等重要 *** 作逻辑分配给它。
经典的守护线程如:GC垃圾回收线程。
thread.setDaemon(true)必须在thread.start()之前设置,否则会抛异常。
在守护线程中产生的线程也是守护线程。
19. ThreadLocal的原理和使用场景ThreadLocal是线程本地存储,在每次线程创建时都会有一个ThreadLocalMap对象,以当前线程作为key,访问内部的value。
使用场景:JDBC Connection、Session
ThreadLocal引起的内存泄露的处理:
- 每次使用完ThreadLocal都调用它的remove()方法清除数据
- 将ThreadLocal变量定义为private static ,这样就一直存在ThreadLocal的强引用,也就能保证任何时候都能通过ThreadLocal的弱引用访问到Entry的value值,进而清除掉。
ThreadLocal引起的一个错误:
-
在多租户项目中,每个租户用的一个唯一的平台号,程序中有地方把当前用户的平台号放在一个ThreadLocal变量中,出现问题:有时候用户的平台号会错乱,就是一个人的平台号会出现在另一个登录用户中,最后定位到问题是在线程池上。ThreadLocal中的值实际上保存在线程对象中。在有线程池的情况下,线程用完以后会回到线程池中,下次需要线程是就从线程池中获取一个。如果ThreadLocal中的值没有被清空,这个值就会保留下来继续使用,导致出现问题。
解决办法:使用完ThreadLocal后调用remove()方法清除数据。
原子性、一致性、可见性
21. 为什么使用线程池?线程池的参数说明?线程的创建和销毁都是比较消耗资源的,线程池可以复用线程,避免频繁的创建和销毁线程,提升效率。
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueueworkQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) { if (corePoolSize < 0 || maximumPoolSize <= 0 || maximumPoolSize < corePoolSize || keepAliveTime < 0) throw new IllegalArgumentException(); if (workQueue == null || threadFactory == null || handler == null) throw new NullPointerException(); this.acc = System.getSecurityManager() == null ? null : AccessController.getContext(); this.corePoolSize = corePoolSize; this.maximumPoolSize = maximumPoolSize; this.workQueue = workQueue; this.keepAliveTime = unit.toNanos(keepAliveTime); this.threadFactory = threadFactory; this.handler = handler; }
线程池参数:
corePoolSize– 池中要保留的线程数,即使它们处于空闲状态,除非设置了 allowCoreThreadTimeOut
maximumPoolSize– 池中允许的最大线程数
keepAliveTime– 当线程数大于核心时,这是多余空闲线程在终止前等待新任务的最长时间
unit– keepAliveTime 参数的时间单位
workQueue– 用于在执行任务之前保存任务的队列。这个队列将只保存 execute 方法提交的 Runnable 任务。
threadFactory– 执行程序创建新线程处理程序时使用的工厂
handler–由于达到线程边界和队列容量而阻塞执行时使用的处理程序
穿透:当请求一个不存在的key时会直接对持久化层发起请求,这样就失去了缓存的意义。比如id是从0开始的,用-1去请求;处理办法有两种,一种是增加校验,另一种是布隆过滤器。
击穿:一个非常热点key,当它失效时数据库会承受大量的并发访问。解决办法:热点数据永不过期,或者加上互斥锁。
雪崩:大量的缓存失效或者缓存不可用时直接请求数据库;解决办法:缓存层设计为高可用,分布式部署;设置热点key永不过期;缓存过期时间设置随机,防止大量数据同时过期。
23. Spring事务什么时候会失效?- 发生自调用,类里边使用this调用本类的方法(this通常省略),此时this对象不是代理类,而是实际类本身。
- 数据库不支持事务(如MySQL使用了MyISAM引擎)
- 没有被Spring管理
- 异常被吃掉,事务不会回滚(或者抛出的异常没有被定义,默认为RuntimeException)
Spring框架是一个IOC容器,用来管理bean。使用DI实现控制反转,可以方便整合各种框架。AOP功能可以减少重复代码,将一下与业务无关的代码通过切面抽取,比如日志、异常等。
SpringMVC是Spring对web框架的一种解决方案。提供了一个总的前端控制器Servlet,用来接受请求,然后定义一套路由策略(url到handle的映射)及适配执行handle,将handle结果使用视图解析技术生成视图展示给前端。
SpringBoot是Spring提供的一个快速开发工具包,让程序员能更方便快捷的开发spring应用,简化了配置,整合了一系列解决方案(starter机制),可以开箱即用。
25. SpringMVC工作流程欢迎分享,转载请注明来源:内存溢出
评论列表(0条)