1. String,StringBuilder,StringBuffer区别是什么?底层数据结构是什么?分别是如何实现的?
String 直接实现了 CharSequence 接口,一旦创建不可变。StringBuilder 和 StringBuffer 都是可变的字符序列,它们都继承于 AbstractStringBuilder,实现了 CharSequence 接口,可变。
StringBuffer 线程安全,执行效率低;StringBuilder线程不安全,执行效率高
使用环境:
操作少量的数据使用 String。
单线程操作大量数据使用 StringBuilder。
多线程操作大量数据使用 StringBuffer。
2. HashSet的底层实现是什么?它与HashMap有什么关系?区别?
hashMap和hashSet的底层数据结构都采用哈希表结构,hashSet底层其实是通过hashMap实现的。它将要存储的对象直接做为map的key,并且创建一个空的object对象作为map的值。二者都无序,key不重复,LinkedHashMap是有序的(哈希表+链表)。
二者最大的区别就在于,HashSet是继承自Collection的接口类,Set中只存储key。
HashMap是继承于Map接口,存储的是key-value键值对。
3.Java 的并发包里面有那些知识点?
转:https://code84.com/269988.html
4.HashCode与HashMap的关系?
hash表:存放hashcode,通过hashcode值加快查找速度
HashMap通过key查询:通过hash表中的hashcode得出key值在数组的索引,然后使用equals便利得出key值对应的value值然后返回。
5. 哈希函数的理解?
Hash函数译为哈希函数,又称散列函数。哈希函数可以把给定的数据转换成固定长度的无规律数值。转换后的无规律数值可以作为数据摘要应用于各种各样的场景。
6.map在put()的做了哪些事?
HashMap的是由数组和链表构成的,JDK7之后加入了红黑树处理哈希冲突。put操作的步骤是这样的:
1.根据key值计算出哈希值作为数组下标。如果数组的这个位置是空的,把k放进去,put操作就完成了。
2.如果数组位置不为空,这个元素必然是个链表。遍历链表逐一比对value,如果value在链表中不存在,就把新建节点,将value放进去,put操作完成。
3.如果链表中value存在,则替换原节点的value,put操作完成。
4.如果链表节点数已经达到8个,首先判断当前hashMap的长度,如果不足64,只进行resize,扩容table,如果达到64就将冲突的链表为红黑树。
7.如果发生hash碰撞,有什么方法可以解决?
解决hash冲突(哈希冲突)有以下四种方法:
1.链地址法:
对于相同的哈希值,使用链表进行连接。(HashMap使用此法)
2.再哈希法
3.建立公共溢出区
4.开放定址法
8.各种类型的锁?
- 乐观锁与悲观锁
悲观锁:不能同时进行多人,执行的时候先上锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁
乐观锁:通过版本号一致与否,即给数据加上版本,同步更新数据以及加上版本号。不会上锁,判断版本号,可以多人操作,类似生活中的抢票。每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量。Redis就是利用这种check-and-set机制实现事务的。(乐观锁可以使用版本号机制和CAS算法实现)
2.自旋锁
3.公平锁与非公平锁
9.synchronize和lock?
lock是一个接口,而synchronized是java的一个关键字。2、synchronized在发生异常时会自动释放占有的锁,因此不会出现死锁;而lock发生异常时,不会主动释放占有的锁,必须手动来释放锁,可能引起死锁的发生。
10.hashTable的数据结构?
哈希表(HashTable)又叫做散列表,是根据关键码值(即键值对)而直接访问的数据结构。也就是说,它通过把关键码映射到表中一个位置来访问记录,以加快查找速度。
哈希表的组成(底层数据结构):数组+链表/红黑树
特点:
链表:增删的效率极高,但是查询的效率极低。
数组:查询效率极高,增删效率低
11.线程安全的map即HashTable和CurrentHashMap,底层的线程安全是如何实现的?
HashTable
1、底层:数组+链表实现,无论key还是value都不能为null,线程安全,实现线程安全的方式是在修改数据时锁住整个HashTable(方法上加了synchronized关键字修饰),效率低,后来针对这一缺点ConcurrentHashMap做了相关优化。
ConcurrentHashMap
1、底层采用分段的数组+链表实现,线程安全
2、Hashtable的synchronized是针对整张Hash表的,即每次锁住整张表让线程独占,ConcurrentHashMap允许多个修改操作并发进行,其关键在于使用了锁分离技术。
12.hashCode的原理?
1.HashCode的存在主要是用于查找的快捷性,如Hashtable,HashMap等,HashCode经常用于确定对象的存储地址;
2.如果两个对象相同, equals方法一定返回true,并且这两个对象的HashCode一定相同;
3.两个对象的HashCode相同,并不一定表示两个对象就相同,即equals()不一定为true,只能说明这两个对象在一个散列存储结构中。
13.什么情况下需要重写类的hashCode()方法?什么时候需要重写equals()方法?
当我们自定义的一个类,想要把它的实例保存在集合中时,我们就需要重写这两个方法;集合(Collection)有两个类,一个是List,一个是Set。
List:集合中的元素是有序的,可以重复的;
Set:无序,不可重复的;
14.ArrayList和hashmap底层结构,以及CurrentHashMap解决了什么问题;
ArrayList底层是数组,是有序的
hashmap由数组+链表组成的
在多线程中,hashmap的put方法可能会造成死循环的问题,put的时候引发扩容。hashtable虽然是线程安全的,但是在多线程中使用的是synchronized,当一个线程抢到锁之后,别的线程会等待使用锁的线程释放后才会执行,相当于单线程,效率不高,而CurrentHashmap是采用的是分段锁的思想,可以支持16个线程同时执行,效果显然是比较快的
15.volatile关键字的理解;用在哪些场景?
volatile关键字是由JVM提供的最轻量级同步机制
被volatile修饰的变量将会有两个特性,第一是保证此变量对所有的线程的可见性;第二是禁止指令重排。volatile保证线程间的数据是可见的(共享的),但不保证数据同步
适用场景:
由于volatile只能保证可见性,则使用时必须遵守以下原则,否则需要考虑使用原子类乃至锁机制。
运算结果不依赖变量的当前值,或者能确保只有单一的线程修改变量的值;
变量不需要与其他状态变量共同参与不变约束。
16.线程的理解以及其实现方式
线程是操作系统能够进行运行运算调度的最小单位,一条线程指的是进程中一个单一顺序的控制流。例如main函数就是一个线程。
Thread类是java.lang.Object类下的,实现线程有三种方法,继承Thread类,实现Runnable接口,实现callable接口。
17.线程同步方法有哪些?
(1)wait():使一个线程处于等待状态,并且释放所持有的对象的lock。
(2)sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要捕捉 InterruptedException异常。
(3)notify():唤醒一个处于等待状态的线程,注意的是在调用此方法的时候,并不能确切的 唤醒某一个等待状态的线程,而是由JVM确定唤醒哪个线程,而且不是按优先级。
(4)notifyAll ():唤醒所有处于等待状态的线程,注意并不是给所有唤醒线程一个对象的锁, 而是让它们竞争。
18.缓存的原理?为什么要用缓存?为什么会比数据库查询快?
原理:缓存的工作原理是当CPU要读取一个数据时,首先从CPU缓存中查找,找到就立即读取并送给CPU处理;没有找到,就从速率相对较慢的内存中读取并送给CPU处理,同时把这个数据所在的数据块调入缓存中,可以使得以后对整块数据的读取都从缓存中进行,不必再调用内存。
功能:主要是两方面,缓存可以实现高性能,高并发
举例:mysql持久化存储,存放在磁盘里面,redis放在内存
19反射机制的理解
在运行过程中,对于任何一个类,都能够知道其所有的属性和方法,对于任意一个对象,都能够调用其属性和方法。这种能够动态的获取和调用对象方法的功能,就是JAVA的反射机制
20.Object中的方法
equals()方法、toString()方法、finalize()方法、hashcode()方法
21.String的toString()方法的实现?底层原理?
tostring()方法是object类里的方法。又因为object类是所有类的子类,这些类默认继承他,因此所有类的对象都可以使用tostring()
在源码的注释中有重要一句话:It is recommended that all subclasses override this method(建议所有的子类都覆盖这个方法),java类根据需要重写toString方法才能使返回值更有意义。即如果不去重写这个方法那么返回值就会是 类名+符号@+对象的哈希码值。
22.NIO与IO的异同
nio和io是java语言中的术语,区别为:
1、面向对象不同,nio面向块(buffer),io面向流(Stream);
2、模式不同:nio有阻塞和非阻塞两种模式,io只有阻塞模式;
3、选择器不同:nio的选择器允许一个单独的线程来监视多个输入通道,io没有选择器。
23.垃圾回收机制的理解
垃圾回收机制
1.垃圾回收机制(Garbage Collction)简称GC,是JavaScript中使用的内存管理系统的基本组部分,是为了防止内存泄漏
2.JavaScript是在创建变量(对象、字符串等)时自动进行了分配内存,并且在不使用他们时“自动释放。”
3.内存在不适用的时候就被垃圾回收器自动回收
24.java8的新特性有哪些?如何使用?
1.Java8 函数式接口− 函数式接口(Functional Interface)就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。函数式接口可以被隐式转换为 lambda 表达式。
2.Lambda 表达式 − Lambda 允许把函数作为一个方法的参数(函数作为参数传递到方法中)。 Stream API −新添加的Stream API(java.util.stream) 把真正的函数式编程风格引入到Java中。
3.方法引用 − 方法引用提供了非常有用的语法,可以直接引用已有Java类或对象(实例)的方法或构造器。与lambda联合使用,方法引用可以使语言的构造更紧凑简洁,减少冗余代码。
4.Date Time API − 加强对日期与时间的处理。
5.Optional 类 − Optional 类已经成为 Java 8 类库的一部分,用来解决空指针异常。
25.static关键字的场景和意义;(拓展:final)
static 关键字主要有两种作用:第一,为某特定数据类型或对象分配单一的存储空间,而
与创建对象的个数无关。第二,实现某个方法或属性与类而不是对象关联在一起,也就是说,
在不创建对象的情况下就可以通过类来直接调用方法或使用类的属性。具体而言,在 Java语
言中,static 主要有 4 种使用情况:成员变量、成员方法、代码块和内部类。
final修饰数据、方法和类(不可变)
26.如何理解事务?
事务具有:
1.原子性:要么全部提交成功,要么全部失败回滚,不能只执行其中的一部分操作
2.一致性:事务的执行不能破坏数据库数据的完整性和一致性,一个事务在执行之前和执行之后,数据库都必须处于一致性状态
3.隔离性:数据库会开启多个事务,事务之间相互隔离,互不影响
4.持久性:当事务确认完成后,对数据的改变是永久性的。
事务就是一组严密的逻辑操作,所有操作必须全部执行成功,否则将会撤销所有操作,也就是事务回滚操作。
27.虚拟机的内存结构
JVM是基于堆、栈的的虚拟机,堆和栈都是Java在内存中存放是数据的地方
堆:存储的全部是对象
栈:可以看成是方法的运行模型,所有方法的调用都是通过栈帧来进行的
28.动态代理的两种实现方式
动态代理的方式有两种:
JDK动态代理:利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。
CGLIB动态代理:利用ASM(开源的Java字节码编辑库,操作字节码)开源包,将代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。
区别:JDK代理只能对实现接口的类生成代理;CGlib是针对类实现代理,对指定的类生成一个子类,并覆盖其中的方法,这种通过继承类的实现方式,不能代理final修饰的类。
29.悲观锁和乐观锁的区别
悲观锁:共享资源每次只给一个线程使用,其它线程阻塞,用完后再把资源转让给其它线程,一般多写的场景下用悲观锁就比较合适
乐观锁适用于多读的应用类型,这样可以提高吞吐量
30.如何解决跨域问题?
1.同源策略:协议、域名、端口号都相同
2.response 添加 header
//*表示支持所有网站访问,也可以额外配置相应网站
resp.setHeader("Access-Control-Allow-Origin", "*");
3.JSONP 方式:修改了 dataType 的数据类型为 jsonp,并且新增了 jsop 属性值为 “backFunction”。
4.nginx反向代理,将请求分发到部署到相应项目的tomcat服务器,当然也不存在跨域问题
31.xml文件解析方式有几种
一、DOM解析
二、SAX解析
三、JDOM解析
四、DOM4J解析
32.synchronize的锁的类型
synchronized同步代码块、修饰普通方法、修饰静态方法
锁状态 :
无锁不可偏向、无锁可偏向 、轻量级锁 、重量级锁
33.秒杀系统的设计
转:https://blog.csdn.net/weixin_42754896/article/details/126110420
34.分库分表
垂直分和水平分
数据切分及整合方案:
1.在每一个应用程序模块中配置管理自己须要的一个(或者多个)数据源。直接訪问各个数据库,在模块内完毕数据的整合(不太现实,因为现在主流的DB架构都是独立一层);
2. 通过中间代理层来统一管理全部的数据源。后端数据库集群对前端应用程序透明;
代理层解决方式:
★ 自行开发中间代理层:
通过自行开发中间代理层能够最大程度的应对自身应用的特定。最大化的定制非常多个性化需求,在面对变化的时候也能够灵活的应对。这应该说是自行开发代理层最大的优势了(自适应高、成本大)。
★ 开源中间代理层:
MySQLProxy
Amoeba
Mycat
35.Spring底层是如何实现的
转:https://blog.csdn.net/PnJgHT/article/details/125647905
36.Tomcat容器启动的时候,spring的启动流程
1.项目启动类的main方法执行
2.执行run方法
3.Spring容器初始化
4.Spring容器初始化后的回调
5.创建WebServer
6.获取WebServerFactory
7.获取WebServer,创建并设置Tomcat相关对象属性
8.封装TomcatWebServer
9.初始化TomcatWebServer并启动Tomcat
37.SpringAop除了动态代理,还用了其余的什么原理?
1、方面(Aspect):一个关注点的模块化,这个关注点实现可能另外横切多个对象。事务管理是J2EE应用中一个很好的横切关注点例子。方面用Spring的Advisor或拦截器实现。
2、连接点(Joinpoint):程序执行过程中明确的点,如方法的调用或特定的异常被抛出。
3、通知(Advice):在特定的连接点,AOP框架执行的动作。各种类型的通知包括“around”、“before”和“throws”通知。通知类型将在下面讨论。许多AOP框架包括Spring都是以拦截器做通知模型,维护一个“围绕”连接点的拦截器链。
38.rpc框架
rpc是远程过程调用,是一种通过网络远程调用其他服务的协议
rpc=socket + 动态代理
RPC框架的核心部分:
1.RPC服务的注解的实现。
2.服务提供者初始化、注册、以及响应远程调用的实现。
3.服务消费者订阅注册中心、监听服务提供者的变化的实现。
4.动态代理的实现。
39.事务的隔离级别和传播机制
四种隔离级别:
ISOLATION_READ_UNCOMMITTED:读未提交
ISOLATION_READ_COMMITTED:读已提交
ISOLATION_REPEATABLE_READ:可重复读
ISOLATION_SERIALIZABLE:串行化
七种传播机制:
PROPAGATION_REQUIRED 表示当前方法必须在一个具有事务的 上下文中运行,如有客户端有事务在进行,那么被调用端将在该事务中运行,否则的话重新开启一个事务。( 如果被调用端发生异常,那么调用端和被调用端事务都将回滚)
PROPAGATION_SUPPORTS 表示当前方法不必需要具有一个事务 上下文,但是如果有一个事务的话,它也可以在这个事务中运行
PROPAGATION_MANDATORY 表示当前方法必须在一个事务中运行,如果没有事务,将抛出异常
PROPAGATION_REQUIRES_NEW 总是开启一个新的事务。如果一个事务已经存在,则将这个存在的事务挂起。
PROPAGATION_NOT_SUPPORTED 总是非事务地执行,并挂起任何存在的事务。
PROPAGATION_NEVER 总是非事务地执行,如果存在一个活动事务,则抛出异常
PROPAGATION_NESTED表示如果当前方法正有一个事务在运行中,则该方法应该运行在一个嵌套事务中 ,被嵌套的事务可以独立于被封装的事务中进行提交或者回滚。如果封装事务存在,并且外层事务抛出异常回滚,那么内层事务必须回滚,反之,内层事务并不影响外层事务。如果封装事务不存在,则同propagation. required的一样
40.docker
本站其他文档有解释:例:docker
41.高峰期如何进行分流
(1).使用集群,Nginx负载均衡功能
(2).分布式的系统架构