数据库
1.mysql的隔离级别有哪些,解读下脏读幻读
①Read Uncommitted(读未提交)
所有事务都可以看到其他未提交事务的执行结果。本隔离级别很少用于实际应用,因为它的性能也不比其他级别好多少。读取未提交的数据,也被称之为脏读(Dirty Read)。
②Read Committed(读已提交)
这是大多数数据库系统的默认隔离级别(但不是MySQL默认的)。它满足了隔离的简单定义:一个事务只能看见已经提交事务所做的改变。这种隔离级别 也支持所谓的不可重复读(Nonrepeatable Read),因为同一事务的其他实例在该实例处理其间可能会有新的commit,所以同一select可能返回不同结果。
③Repeatable Read(可重读)
这是MySQL的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。不过理论上,这会导致另一个棘手的问题:幻读 (Phantom Read)。简单的说,幻读指当用户读取某一范围的数据行时,另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的“幻影” 行。InnoDB和Falcon存储引擎通过多版本并发控制(MVCC,Multiversion Concurrency Control)机制解决了该问题。
④Serializable[ˈsɪərɪəlaɪzəbl](可串行化)
这是最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象和锁竞争。
这四种隔离级别采取不同的锁类型来实现,若读取的是同一个数据的话,就容易发生问题。例如:
脏读(Drity Read):某个事务已更新一份数据,另一个事务在此时读取了同一份数据,由于某些原因,前一个RollBack了操作,则后一个事务所读取的数据就会是不正确的。
不可重复读(Non-repeatable read):在一个事务的两次查询之中数据不一致,这可能是两次查询过程中间插入了一个事务更新的原有的数据。
幻读(Phantom Read):在一个事务的两次查询中数据笔数不一致,例如有一个事务查询了几列(Row)数据,而另一个事务却在此时插入了新的几列数据,先前的事务在接下来的查询中,就会发现有几列数据是它先前所没有的。
在MySQL中,实现了这四种隔离级别,分别有可能产生问题如下所示:
2.mysql和orcale的区别
①本质区别:orcale数据库是收费的,mysql数据库不收费
②安全性出发:orcale数据库安全性比mysql高
MySQL使用三个参数来验证用户,即用户名,密码和位置;Oracle使用了许多安全功能,如用户名,密码,配置文件,本地身份验证,外部身份验证,高级安全增强功能等。
③语法区别 :Orcale语法更为灵活,例如分页mysql用的是limit关键字,orcale用的是rownum关键字
④存储上的区别 :与Oracle相比,MySQL没有表空间,角色管理,快照,同义词和包以及自动存储管理。
⑤字符类型不同 mysql:CHAR和VARCHAR orcale:CHAR,NCHAR,VARCHAR2和NVARCHAR2;
⑥事务提交: MySQL默认是自动提交,而Oracle默认不自动提交,需要用户手动提交,需要在写commit;指令或者点击commit按钮
3.数据库优化之索引*
1、在表中建立索引,优先考虑where、group by使用到的字段。
2、尽量避免使用select *,返回无用的字段会降低查询效率。
3、尽量避免使用not exists 和not in,会导致数据库引擎放弃索引进行全表扫描。
4、尽量避免使用or,会导致数据库引擎放弃索引进行全表扫描。
5、尽量避免在字段开头模糊查询,会导致数据库引擎放弃索引进行全表扫描。
6、尽量避免进行null值的判断,会导致数据库引擎放弃索引进行全表扫描。
7. 应尽量避免在 where 子句中使用!=或<>操作符,否则将引擎放弃使用索引而进行全表扫描。
8、避免使用函数
4.sql优化实现
1.SQL语句尽量用大写的:因为oracle总是先解析SQL语句,把小写的字母转换成大写的再执行。
2.使用表的别名 :当在SQL语句中连接多个表时, 尽量使用表的别名并把别名前缀于每个列上。这样一来,就可以减少解析的时间并减少那些由列歧义引起的语法错误。
5.索引
主键索引 PRIMARY KEY 它是一种特殊的唯一索引,不允许有空值。一般是在建表的时候同时创建主键索引。注意:一个表只能有一个主键
唯一索引 UNIQUE(适用于MYSQL ORCALE) 唯一索引列的值必须唯一,但允许有空值。如果是组合索引,则列值的组合必须唯一。可以通过ALTER TABLE table_name ADD UNIQUE (column);创建唯一索引
创建唯一组合索引(适用于MYSQL ORCALE)
ALTER TABLE table_name ADD UNIQUE (column1,column2)
普通索引 INDEX(只适用于MYSQL)】
这是最基本的索引,它没有任何限制。可以通过ALTER TABLE table_name ADD INDEX index_name (column);创建普通索引
组合索引 INDEX(只适用于MYSQL)
即一个索引包含多个列,多用于避免回表查询。可以通过ALTER TABLE table_name ADD INDEX index_name(column1,column2, column3);
组合索引 INDEX(只适用于ORCALE)
即一个索引包含多个列,多用于避免回表查询。可以通过ALTER TABLE table_name ADD INDEX index_name(column1,column2, column3);
全文索引 FULLTEXT(只适用于MYSQL)
也称全文检索,是目前搜索引擎使用的一种关键技术。可以通过ALTER TABLE table_name ADD FULLTEXT (column)
删除索引(只适用于MYSQL)
索引一经创建不能修改,如果要修改索引,只能删除重建。可以使用
DROP INDEX index_name ON table_name;删除索引。
6.delete与truncate删除表中数据的区别
1.delete与truncate都可以用来删除表中数据
2.delete删除你表中数据之后,再次插入数据索引会接着之前的,而truncate删除表中后重新插入数据索引会从初始大小开始。
3.delete在删除数据后会将删除操作作为事务存储在日志中,这样就可以进行事务回滚。而 truncate则不可以事务回滚。
7.数据库的四大特性ACID
原子性:事务内包含的所有操作要么全部成功,要么全部失败回滚;实现:日志,将所有的更新操作全部写入日志当中,若因为一些系统奔溃/断电等原因导致事务中的部分更新操作已经执行,部分操作未执行,则通过回溯日志,将操作回滚,使系统保证原子性以及一致性;
一致性:不管任何时间有少个并发的事务,系统也必须保持一致;
隔离性:多个并发的事务的操作,在同一时间只能有一个事务执行(及串行的执行);
持久性:事务正确执行后,事务中对数据的操作不会回滚;
MQ
1.rocketMq实现原理
RocketMQ由NameServer注册中心集群、Producer生产者集群、Consumer消费者集群和若干Broker(RocketMQ进程)组成,它的架构原理是这样的:
Broker在启动的时候去向所有的NameServer注册, 并保持长连接,每30s发送一次心跳
Producer在发送消息的时候从NameServer获取Broker服务器地址,(根据负载均衡算法选择一台服务器)来发送消息
Conusmer消费消息的时候同样从NameServer获取Broker地址,然后主动拉取消息来消费
2.MQ如何防止消息方消息重复消费
解决消费方幂等性的问题:
产生:当生产方和消费方有可能因为一个网络延迟等原因,MQ服务器无法即使接收到消费方应答,导致MQ重试,在重试过程中造成重复消费问题。
解决思路:
①如果消费方是做数据库操作,那么可以把消息的ID作位表的唯一主键,这样我们可以在重试的情况下,会触发主键冲突从而避免数据出现脏数据。
②如果不是做数据库操作,可以借助第三方的缓存应用,列入redis,来做消费记录,每次消息被消费完成时候,把当前消息的ID作位key存入redis,每次消费前,先到redis查询有没有该消息的消费记录
3.rockermq消息丢失解决办法
生产者丢失
程序发送失败抛异常了没有重试处理,或者发送的过程成功但是过程中网络闪断MQ没收到,消息就丢失了。
(1)MQ回调通知消息发送结果,对应更新数据库MQ发送状态
(2)JOB轮询超过一定时间(时间根据业务配置)还未发送成功的消息去重试
(3)在监控平台配置或者JOB程序处理超过一定次数一直发送不成功的消息,告警,人工介入。
MQ丢失
- 同步刷盘时使用 GroupCommitService
- 异步刷盘时使用 FlushRealTimeService
如果生产者保证消息发送到MQ,而MQ收到消息后还在内存中,这时候宕机了又没来得及同步给从节点,就有可能导致消息丢失。
RocketMQ分为同步刷盘和异步刷盘两种方式,默认的是异步刷盘,就有可能导致消息还未刷到硬盘上就丢失了,可以通过设置为同步刷盘的方式来保证消息可靠性,这样即使MQ挂了,恢复的时候也可以从磁盘中去恢复消息。
消费者丢失
消费者丢失消息的场景:消费者刚收到消息,此时服务器宕机,MQ认为消费者已经消费,不会重复发送消息,消息丢失。
RocketMQ默认是需要消费者回复ack确认,
消费方不返回ack确认,就会重新发送消息。
重发的机制根据MQ类型的不同发送时间间隔、次数都不尽相同,如果重试超过次数之后会进入死信队列,需要手工来处理了
5.如果Broker宕了,NameServer是怎么感知到的?
Broker会定时(30s)向NameServer发送心跳
然后NameServer会定时(10s)运行一个任务,去检查一下各个Broker的最近一次心跳时间,如果某个Broker超过120s都没发送心跳了,那么就认为这个Broker已经挂掉了。
6. 生产者发送消息的方式?
同步发送
同步发送:消息发出数据后会在收到接收方发回响应之后才发下一个数据包。一般用于重要通知消息,例如重要通知邮件、营销短信。
异步发送
异步发送:出数据后,不等接收方发回响应,接着发送下个数据包,一般用于可能链路耗时较长而对响应时间敏感的业务场景,例如用户视频上传后通知启动转码服务。
单向发送
单向发送:只负责发送消息而不等待服务器回应且没有回调函数触发,适用于某些耗时非常短但对可靠性要求并不高的场景,例如日志收集。
7. 消费者消费模式有几种?
集群消费
一个 Consumer Group 中的各个 Consumer 实例分摊去消费消息,即一条消息只会投递到一个 Consumer Group 下面的一个实例。
广播消费
消息将对一 个Consumer Group 下的各个 Consumer 实例都投递一遍。即即使这些 Consumer 属于同一个Consumer Group ,消息也会被 Consumer Group 中的每个 Consumer 都消费一次。
8. 消费者获取消息有几种模式?
消费者获取消息有两种模式:推送模式和拉取模式。
1. PushConsumer
推送模式(虽然 RocketMQ 使用的是长轮询)的消费者。消息的能及时被消费。使用非常简单,内部已处理如线程池消费、流控、负载均衡、异常处理等等的各种场景。
2. PullConsumer
拉取模式的消费者。应用主动控制拉取的时机,怎么拉取,怎么消费等。主动权更高。但要自己处理各种场景。
基础
1.Filter与interceptor的区别(过滤器和拦截器的区别)
① 拦截器是基于java反射机制的,而过滤器是基于函数回调的。
② 过滤器依赖与servlet容器,而拦截器不依赖与servlet容器。
③ 拦截器只能对Action请求起作用,而过滤器则可以对几乎所有请求起作用。
④ 拦截器可以访问Action上下文、值栈里的对象,而过滤器不能。
⑤ 在Action的生命周期中,拦截器可以多次调用,而过滤器vv只能在容器初始化时被调用一次。
2接口和抽象类的区别
比较点 抽象类 接口
①默认方法 抽象类可以有默认的方法实现-------java 8之前,接口中不存在方法的实现
②实现方式 子类使用extends关键字来继承抽象类.如果子类不是抽象类,子类需要提供抽象类中所声明方法的实现------子类使用implements来实现接口,需要提供接口中所有声明的实现.
③构造器 抽象类中可以有构造器----接口中不能
④和正常类区别 抽象类不能被实例化-------接口则是完全不同的类型
⑤访问修饰符 抽象方法可以有public,protected [prəˈtektɪd] 和default等修饰----接口默认是public,不能使用其他修饰符
⑥多继承 一个子类只能存在一个父类-----一个子类可以存在多个接口
⑦添加新方法 抽象类中添加新方法,可以提供默认的实现,因此可以不修改子类现有的代码----如果往接口中添加新方法,则子类中需要实现该方法
3.什么是cookie?简单的说下Cookie的生命周期?
Cookie是由服务器创建,保留客户端,并会标注出Cookie来源(哪个服务器的Cookie)。
当客户端向服务器发出请求时会把所有这个服务器Cookie包含在请求中发送给服务器,这样服务器就可以识别客户端了!
4.Cookie的生命周期
Cookie不只是有name和value,Cookie还是生命。所谓生命就是Cookie在客户端的有效时间,可以通过setMaxAge(int)来设置Cookie的有效时间。
Cookie.setMaxAge(-1):cookie的maxAge属性的默认值就是-1,表示只在浏览器内存中存活。一旦关闭浏览器窗口,那么cookie就会消失。
Cookie.setMaxAge(60*60):表示cookie对象可存活1小时。当生命大于0时,浏览器会把Cookie保存到硬盘上,就算关闭浏览器,就算重启客户端电脑,cookie也会存活1小时;
Cookie.setMaxAge(0):cookie生命等于0是一个特殊的值,它表示cookie被作废!无论是在浏览器内存中,还是在客户端硬盘上都会删除这个Cookie。
5.什么是session?简单的说下session的生命周期?
① 当首次使用session时,服务器端要创建session,session是保存在服务器端,而给客户端的session的id (一个cookie中保存了sessionId)。客户端带走的是sessionId,而数据是保存在session中。当客户端再次访问服务器时,在请求中会带上sessionId,而服务器会通过sessionId找到对应的session,而无需再创建新的session。
① Session的销毁只有两种情况:第一:session调用了 session.invalidate()方法. 第二:前后两次请求超出了session指定的生命周期时间. 其中Session的生命周期时间可以在web.xml配置. 默认30分钟 在web.xml可以做如下配置:
6.cookie和session的区别
①Cookie可以存储在浏览器或者本地,Session只能存在服务器
②session 能够存储任意的 java 对象,cookie 只能存储 String 类型的对象
③Session比Cookie更具有安全性(Cookie有安全隐患,通过拦截或本地文件找得到你的cookie后可以进行攻击)
④Session占用服务器性能,Session过多,增加服务器压力
⑤单个Cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个Cookie,Session是没有大小限制和服务器的内存大小有关
7.get和set乱码如何解决
1.post请求:response.setCharacterEncoding("utf-8");
2、set 请求修改tomcat的配置文件server.xml:只需增加 URIEncoding="UTF-8" 这一句,然后重启tomcat即可。
8.new String("abc"),内存会发生什么
String是一个特殊的包装类数据。可以用:
String str = new String("abc");
String str = "abc";
两种的形式来创建,第一种是用new()来新建对象的,它会在存放于堆中。每调用一次就会创建一个新的对象。
而第二种是先在栈中创建一个对String类的对象引用变量str,然后查找栈中有没有存放"abc",如果没有,则将"abc"存放进栈,并令str指向”abc”,如果已经有”abc” 则直接令str指向“abc”。
String str1 = "abc";
String str2 = "abc";
System.out.println(str1==str2); //true
可以看出str1和str2是指向同一个对象的。
String str1 =new String ("abc");
String str2 =new String ("abc");
System.out.println(str1==str2); // false
用new的方式是生成不同的对象。每一次生成一个。
因此用第二种方式创建多个”abc”字符串,在内存中其实只存在一个对象而已. 这种写法有利与节省内存空间. 同时它可以在一定程度上提高程序的运行速度,因为JVM会自动根据栈中数据的实际情况来决定是否有必要创建新对象。而对于String str = new String("abc");的代码,则一概在堆中创建新对象,而不管其字符串值是否相等,是否有必要创建新对象,从而加重了程序的负担。
另一方面, 要注意: 我们在使用诸如String str = "abc";的格式定义类时,总是想当然地认为,创建了String类的对象str。担心陷阱!对象可能并没有被创建!而可能只是指向一个先前已经创建的对象。只有通过new()方法才能保证每次都创建一个新的对象。由于String类的immutable性质,当String变量需要经常变换其值时,应该考虑使用StringBuffer类,以提高程序效率。
9.==和equals的区别
==比较的是对象地址,equals比较的是对象的内容
10.jvm的内存模型*
①程序计数器(PC)
用于记录下一条要运行的指令。每个线程都需要一个程序计数器,各个线程之中的计数器相互独立,是线程中私有的内存空间
②java虚拟机栈
保存了局部变量、部分结果,并参与方法的调用和返回
③本地方法栈
用于管理Java函数的调用,但不是由Java实现的,而是由C实现的
④java堆
为所有创建的对象和数组分配内存空间,被JVM中所有的线程共享
⑤ 方法区
类的类型信息、常量池、域信息、方法信息,其中运行时常量池就在方法区,对永久区的GC回收,一是GC对永久区常量池的回收;二是永久区对元数据的回收
11.String,StringBuffer,和StringBuilder的区别*
String 字符串常量,StringBuffer 字符串变量(线程安全),StringBuilder 字符串变量(非线程安全)
12.单例模式的五种实现方式
1.饿汉式(线程安全,调用效率高,但是不能延时加载):
2.懒汉式(线程安全,调用效率不高,但是能延时加载):
3.Double CheckLock实现单例:DCL也就是双重锁判断机制(由于JVM底层模型原因,偶尔会出问题,不建议使用):
4.静态内部类实现模式(线程安全,调用效率高,可以延时加载)
5.枚举类(线程安全,调用效率高,不能延时加载,可以天然的防止反射和反序列化调用)
13.jdbc执行顺序:* 1)加载(注册)数据库驱动(到JVM)。 2)建立(获取)数据库连接。 3)创建(获取)数据库操作对象。 4)定义操作的SQL语句。 5)执行数据库操作。 6)获取并操作结果集。
14.java的面向对象编程有什么特征*
访问修饰符
封装
把对象的属性和操作(或服务)结合为一个独立的整体
特点:对成员变量实行更准确的控制。
封装可以隐藏内部程序实现的细节。
良好的封装能够减少代码之间的耦合度。
外部成员无法修改已封装好的程序代码。
方便数据检查,有利于保护对象信息的完整性,同时也提高程序的安全性。
便于修改,体高代码的可维护性。
继承
就是子类继承父类的属性和行为,使得子类对象具有与父类相同的属性、相同的行为。子类可以直接访问父类中的非私有的属性和行为。
特点:1.提高代码的复用性。
2.类与类之间产生关系,为多态做了完美的铺垫
多态
多态指同一行为具有多种不同的表现形式
多态前提:继承或者实现
15.java8的新特性 **
1.Lambda表达式:java8引入了一个新的操作符"->",左侧:参数列表,右侧:执行的功能
一:forEach() 循环遍历
List costBeforeTax = Arrays.asList(100, 200, 300, 400, 500);
costBeforeTax.forEach((x) -> System.out.println(x));
运行结果: 100 200 300 400 500
二:filte() 过滤
List costBeforeTax = Arrays.asList(100, 200, 300, 400, 500);
costBeforeTax.stream().filter((x) -> x > 100).forEach((a)->System.out.print(a + " "));
运行结果: 200 300 400 500
三:lambda内部表达式中不能改变外部的变量
List costBeforeTax = Arrays.asList(100, 200, 300, 400, 500);
int sum = 10;costBeforeTax.stream().forEach((x) -> sum +=x);
这种情况会报错
四:map() 将集合类中的元素进行转换
List idcards= users.stream().map(User::getIdcard).collect(Collectors.toList())
List costBeforeTax = Arrays.asList(100, 200, 300, 400, 500);
costBeforeTax.stream().map(x -> x + 0.12 * x).forEach(x->System.out.print(x + " "));
运行结果:112.0 224.0 336.0 448.0 560.0
五:distinct() 对集合进行去重
List numbers = Arrays.asList(9, 10, 3, 4, 7, 3, 4);
List newlist = numbers.stream().distinct().collect(Collectors.toList());System.out.print(newlist);
2.函数式接口:如果一个接口只有一个抽象方法,则该接口称之为函数式接口
3.方法引用与构造器引用
4.Stream API流式计算:Stream API是集合的抽象概念,可以指定集合进行的操作,可以执行复杂的查找、过滤和映射数据等操作。使用Stream API对集合数据进行操作,类似于SQL执行的数据库查询
5.接口中的默认方法与静态方法
6.新日期API
7.HashMap采用尾部插入法,具体结构由数组,链表转为数组链表+红黑树
8.ArrayList扩容倍数由1.5+1转变为1.5倍
16.get请求和post请求的区别*
1. Get请求不安全的。2. Get传送的数据量较小。 3. Get限制Form表单的数据集的值必须为ASCII字符;而Post支持整个ISO10646字符集。4. Get执行效率却比Post方法好。
17.创建一个对象有几种方式*
1.用new语句创建对象,这是最常用的创建对象的方式。
2.运用反射手段,调用Java.lang.Class或者java.lang.reflect.Constructor类的newInstance()实例方法。
3.调用对象的clone()方法。
4.运用反序列化手段,调用java.io.ObjectInputStream对象的readObject()方法.
18.java封装
是指一种将抽象性函式接口的实现细节部份包装、隐藏起来的方法
1. 良好的封装能够减少耦合。
2. 类内部的结构可以自由修改。
3. 可以对成员变量进行更精确的控制。
4. 隐藏信息,实现细节。
19.Collections和Collection的区别
Collections则是集合类的一个工具类,提供了一系列静态方法,用于对集合中元素进行排序、搜索以及线程安全等各种操作。
Collection 是各种集合接口的父接口,继承它的接口主要有Set和List,提供了关于集合的一些操作,如删除,插入,判断一个元素是否是其成员,遍历等。
20.try,catch,finally
在catch中有return的状况下,finally中的内容仍是会执行,而且是先执行finally再return。class
须要注意的是,若是返回的是一个基本数据类型,则finally中的内容对返回的值没有影响。由于返回的是 finally执行以前生成的一个副本。
当catch和finally都有return时,return的是finally的值。
21.泛型的作用
1,类型安全。
泛型的主要目标是提高 Java 程序的类型安全。编译时的强类型检查;通过知道使用泛型定义的变量的类型限制,编译器可以在一个高得多的程度上验证类型假设。
2,消除强制类型转换。
泛型的一个附带好处是,消除源代码中的许多强制类型转换。这使得代码更加可读,并且减少了出错机会。
3,潜在的性能收益。
泛型为较大的优化带来可能。在泛型的初始实现中,编译器将强制类型转换(没有泛型的话,程序员会指定这些强制类型转换)插入生成的字节码中。但是更多类型信息可用于编译器这一事实,为未来版本的 JVM 的优化带来可能。由于泛型的实现方式,支持泛型(几乎)不需要 JVM 或类文件更改。所有工作都在编译器中完成,编译器生成类似于没有泛型(和强制类型转换)时所写的代码,只是更能确保类型安全而已。
22.堆与栈的区别
堆:(对象)
引用类型的变量,其内存分配在堆上或者常量池(字符串常量、基本数据类型常量),需要通过new等方式来创建。
堆内存主要作用是存放运行时创建(new)的对象。
(主要用于存放对象,存取速度慢,可以运行时动态分配内存,生存期不需要提前确定)
栈:(基本数据类型变量、对象的引用变量)
基本数据类型的变量(int、short、long、byte、float、double、boolean、char等)以及对象的引用变量,其内存分配在栈上,变量出了作用域就会自动释放。
栈内存的主要作用是存放基本数据类型和引用变量。栈的内存管理是通过栈的"后进先出"模式来实现的。
(主要用来执行程序,存取速度快,大小和生存期必须确定,缺乏灵活性)
图例:
JVM:
是基于堆栈的虚拟机,每个Java程序在一个独立的JVM实例上运行,每个JVM实例对应一个堆,
同个java程序内的多线程运行在同个JVM实例上,多个线程之间共享堆内存(多线访问堆时,要实现数据的同步)。
GC:
Garbage Collection,垃圾收集,垃圾回收
为什么又栈内存和堆内存之分?
当一个方法执行时,每个方法都会建立自己的内存栈,在这个方法定义的变量将会放到这块栈内存里,随着方法的结束,这个方法的内存栈也将自动销毁。(不需要GC回收)
因此,所有在方法中定义的局部变量放在栈内存中;
当我们在程序中创建一个对象时,这个对象会被保存到运行时数据区中,以便反复利用(复用,因为创建对象的成本通常较大),这个运行时数据区就是堆内存。堆内存中的对象不会随着方法的结束而销毁,即使方法结束后,这个对象还可能被另外一个引用变量所引用(在方法的参数传递时很常见),则这个对象依然不会被销毁。只有当一个对象没有任何引用变量去引用它时,系统的垃圾回收器(GC)才会在合适的时候回收它。
为什么上面说创建对象的开销(成本)比较大?
来看看如何创建对象、创建对象的过程:
创建对象的根本途径是构造器,通过new关键字来调用某个类的构造器即可创建这个类的实例。但对象不是完全由构造器来负责创建的,实际上,当程序员调用构造器时,系统会先为该对象分配内存空间,并为这个对象执行默认初始化,这个对象已经产生了---这些是在构造器执行之前就完成的,也就是说,当系统开始执行构造器的执行体之前,系统已经创建了一个对象,只是这对象还不能被外部程序访问,只能在构造器中通过this来引用。当构造器的执行体执行结束后,这个对象作为构造器的返回值被返回,通常还会赋给另外一个引用类型的变量,从而让外部程序可以访问。(当然可以通过设置构造器的访问权限private,阻止其他类创建该类的实例)
23.GIT和SVN的区别
Git是分布式的,SVN是集中式的
这是 Git 和 SVN 最大的区别。若能掌握这个概念,两者区别基本搞懂大半。因为 Git 是分布式的,所以 Git 支持离线工作,在本地可以进行很多操作,包括接下来将要重磅推出的分支功能。而 SVN 必须联网才能正常工作。
Git复杂概念多,SVN简单易上手
所有同时掌握 Git 和 SVN 的开发者都必须承认,Git 的命令实在太多了,日常工作需要掌握add,commit,status,fetch,push,rebase等,若要熟练掌握,还必须掌握rebase和merge的区别,fetch和pull的区别等,除此之外,还有cherry-pick,submodule,stash等功能,仅是这些名词听着都很绕。
在易用性这方面,SVN 会好得多,简单易上手,对新手很友好。但是从另外一方面看,Git 命令多意味着功能多,若我们能掌握大部分 Git 的功能,体会到其中的奥妙,会发现再也回不去 SVN 的时代了。
Git分支廉价,SVN分支昂贵
在版本管理里,分支是很常使用的功能。在发布版本前,需要发布分支,进行大需求开发,需要 feature 分支,大团队还会有开发分支,稳定分支等。在大团队开发过程中,常常存在创建分支,切换分支的需求。
24.Java中基本数据类型和包装类型的区别
⒈ 包装类是对象,拥有方法和字段,对象的调用都是通过引用对象的地址;基本类型不是
⒉ 包装类型是引用的传递;基本类型是值的传递
⒊ 声明方式不同:
基本数据类型不需要new关键字;
包装类型需要new在堆内存中进行new来分配内存空间
⒋ 存储位置不同:
基本数据类型直接将值保存在值栈中;
包装类型是把对象放在堆中,然后通过对象的引用来调用他们
⒌ 初始值不同:
int的初始值为0、boolean的初始值为false
包装类型的初始值为null
25.String Double类型比较
Integer i=-129;
Integer k=-129;
System.out.println(i==k); false
Integer i=-29;
Integer k=-29;
System.out.println(i==k); true
如果你Long的值在[-128,127]这个范围内,进行==比较,结果也是true哦。常量池有范围规定
java为了提高效率,初始化了 -128~127之间的整数对象,所以在赋值时,会先调用 Integer 的 valueOf()方法,判断是否符合 取值范围,如果符合进入IntegerCache的数组中根据 [i + (-IntegerCache.low)]下标取值,如果不符合,就new一个新的对象。
25.throw和throws
1、抛出的东西不同:throw抛出的是具体的异常对象,而throws抛出的是抽象的异常类;
2、使用位置不同:throw一般用在方法体中,也可用在代码块中,但是如果抛出的是检查时异常类创建的对象,则必须使用try-catch自行处理;throws只能用在方法的参数列表后面。
26.object内置方法
protected Object clone() //创建并返回此对象的一个副本。
boolean equals(Object obj) //指示某个其他对象是否与此对象“相等”。
protected void f inalize() //当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法。
Classextends Object> getClass() //返回一个对象的运行时类。
int hashCode() //返回该对象的哈希码值。
void notify() //唤醒在此对象监视器上等待的单个线程。
void notifyAll() //唤醒在此对象监视器上等待的所有线程。
String toString() //返回该对象的字符串表示。
void wait() //导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法。
27.maven引入本地jar包的方法
(1).上传到maven中心仓库
mvn install:install-file -Dfile=F:\WorkProject\pcc-api\src\main\resources\libs\ss_css2.jar -DgroupId=com.extend - DartifactId=ss_css2 -Dversion=1.0.0 -Dpackaging=jar
(2)项目下新建一个lib目录
将索要引入的jar放入lib中
dingding 自定义
dingding 自定义
2.8 自定义
system 必须是system
${project.basedir}/lib/taobao-sdk-java.jar jar包的路径(idea编写的时候会有提示的)
28.基本数据类型和引用数据类型的区别
String类型就是引用类型。简单来说,所有的非基本数据类型都是引用数据类型。
No. | 数据类型 | 大小/位 | 可表示数据范围 | 默认值 |
1 | byte (字节型) | 8 | -128~127 | 0 |
2 | short (短整型) | 16 | -32768~32767 | 0 |
3 | int (整型) | 32 | -2147483648~2147483647 | 0 |
4 | long (长整型) | 64 | -9223372036854775808~9223372036854775807 | 0 |
5 | float (单精度) | 32 | -3.4E38~3.4E38 | 0.0 |
6 | double (双精度) | 64 | -1.7E308~1.7E308 | 0.0 |
7 | char (字符) | 16 | 0~255 | '\u0000' |
8 | boolean (布尔) | - | true或false | false |
(1)在方法中定义的非全局基本数据类型变量的具体内容是存储在栈中的
只要是引用数据类型变量,其具体内容都是存放在堆中的,而栈中存放的是其具体内容所在内存的地址
(2)在方法中定义的非全局基本数据类型变量,调用方法时作为参数是按数值传递的
引用数据类型变量,调用方法时作为参数是按引用传递的,传递的是引用的副本
springboot
微服务保持数据一致性*
TCC模式:分为try,Confirm[kənˈfɜːm],Cancel[ˈkænsl]
第一阶段(try)都成功的时候才进行第二阶段确认(Confirm)操作,如果不成功的话就进行补偿(Cancel)操作,而在try阶段是不会进行真正的业务处理的。
如果Try在所有服务中都成功,那么执行Confirm操作,Confirm操作不做任何的业务检查(因为try中已经做过),只是用Try阶段剩下的业务代码进行业务处理;否则进行Cancel操作,Cancel操作释放Try阶段预留的业务资源。
1.Confirm 失败:则回滚所有 confirm 操作并执行 cancel 操作。
2.Cancel 失败:从业务服务需要提供自动 cancel 机制,以保证 cancel 成功。
1.springboot怎么配置事务
1.在application启动类配置@EnableTransactionManagement注解 2.在service使用@Transactional注解
2.springboot中yml和properties区别*
①properties文件中是以“.”进行分割的,在yml中使用“:”进行分割;②properties文件通过“=”赋值,yml的数据格式类似json,通过“:”赋值,值前面需要加一个空格;yml文件缩进最好用空格;③properties只支持键值对,yml配置文件支持列表;④properties不保证加载顺序,yml有先后顺序。
3.springboot实现原理*
@SpringBootApplication是一个复合注解,在@SpringBootApplication中有一个注解@EnableAutoConfiguration,意思就是开启自动配置,这个注解也是一个复合注解,其中的关键功能由@Import提供,其导入的AutoConfigurationImportSelector的selectImports()方法通过SpringFactoriesLoader.loadFactoryNames()扫描所有META-INF/spring.factories的jar包。其中有一个jar为spring-boot-autoconfigure-x.x.x.x.jar里就有一个这样的spring.factories文件。这个spring.factories文件是以key=value的形式存在,其中一个key是EnableAutoConfiguration类的全类名,value是一个xxxxAutoConfiguration结尾的类列表,这些类名以逗号分隔
这个@EnableAutoConfiguration注解通过@SpringBootApplication被间接的标记在了Spring Boot的启动类上。在SpringApplication.run(...)的内部就会执行selectImports()方法,找到所有JavaConfig自动配置类的全限定名对应的class,然后将所有自动配置类加载到Spring容器中。
4.什么是 Spring Boot?
Spring Boot 是 Spring 开源组织下的子项目,是 Spring 组件一站式解决方案,主要是简化了使用 Spring 的难度,简化配置,提供了各种启动器,上手速度快。
5.Spring Boot 有哪些优点?
①易上手,开发效率高。②不需要繁琐的配置。③提供了很多项目通用的非业务性功能,例如:内嵌服务器、安全管理、运行数据监控、运行状况检查和外部化配置等。④没有代码生成,也不需要XML配置。⑤避免大量的 Maven 导入和各种版本冲突。
6.Spring Boot 的核心注解是哪个?它主要由哪几个注解组成的*
启动类上面的注解是@SpringBootApplication,也是 Spring Boot 的核心注解,主要组合包含了以下 3 个注解:
①@SpringBootConfiguration:组合了 @Configuration 注解,实现配置文件的功能。②@EnableAutoConfiguration:打开自动配置的功能,也可以关闭某个自动配置的选项,如关闭数据源自动配置功能: @SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })。③@ComponentScan[kəmˈpoʊnənt][skæn]:Spring组件扫描。
7.什么是 JavaConfig?
Spring JavaConfig 是 Spring 社区的产品,提供了配置 Spring IoC 容器的Java 方法。可以避免使用 XML 配置。使用 JavaConfig 的优点在于:
①面向对象的配置。由于配置被定义为 JavaConfig 中的类,因此用户可以充分利用 Java 中的面向对象功能。一个配置类可以继承另一个,重写它的@Bean 方法等。
②减少或消除 XML 配置。
③类型安全和重构友好。JavaConfig 提供了一种类型安全的方法来配置 Spring容器。
8.你如何理解 Spring Boot 配置加载顺序?
在 Spring Boot 里面,可以使用以下几种方式来加载配置。①properties文件;②YAML文件;③系统环境变量;④命令行参数;等等……
9.YAML 配置的优势在哪里 ?
①配置有序,在一些特殊的场景下,配置有序很关键②支持数组,数组中的元素可以是基本数据类型也可以是对象③相对于properties文件相对于简介一点
10.Spring Boot 是否可以使用 XML 配置
Spring Boot 推荐使用 Java 配置,但是 也可以使用 XML 配置,通过 @ImportResource 注解可以引入一个 XML 配置。
11.spring boot 核心配置文件是什么?bootstrap.properties 和 application.properties 有何区别 ?
spring boot 核心的两个配置文件:
bootstrap (. yml 或者 . properties):比applicaton文件优先加载,配置在应用程序上下文的引导阶段生效。且 boostrap 里面的属性不能被覆盖;
application (. yml 或者 . properties): 由ApplicatonContext 加载,主要用于 spring boot 项目的自动化配置。
12.Spring Boot 中如何解决跨域问题 ?
实现WebMvcConfigurer接口然后重写addCorsMappings方法解决跨域问题。
13.如何重新加载 Spring Boot 上的更改,而无需重新启动服务器?Spring Boot项目如何热部署?
org.springframework.boot spring-boot-devtools
14.springboot的常用注解
启动类
@SpringBootApplication(scanBasePackages = "com.oct"):是Sprnig Boot项目的核心注解,目的是开启自动配置
@MapperScan("com.oct.tour.*.dao"):扫描的Mapper类的包的路径
controller
@RestController:同于@Controller + @ResponseBody
@RequestMapping("/park") 映射请求
@Autowired 自动装配
controller方法中
@RequestBody WxPaymentCallbackDTO wxPaymentCallbackDTO 前端穿json到后端封装为具体的JavaBean
@QueryParam("page") Integer page 传单值
service
@Service 标记当前类是一个service类,自动注入spring
dao
@Mapper
model
EqualsAndHashCode(callSuper = true)
@Data 省去了set get方法
@TableName(value = "TB_IDENTICAL", autoResultMap = true) 指定表名
@KeySequence(value = "SEQ_TB_IDENTICAL")
Configuration
@Component 实现bean的注入
@Data
@ConfigurationProperties("park.callback") 读取配置文件指定具体路径
util
@Component
15.@Autowired和@Resouce的区别
缺点
11. 你所知道的微服务技术栈?
12. Eureka和ZooKeeper都可以提供服务注册与发现的功能,请说说两个的区别
1.Eureka可以很好的应对因网络故障导致部分节点失去联系的情况,而不会像ZooKeeper一样使得整个注册系统瘫痪
2.ZooKeeper有角色差异,Eureka各个节点平等
3.ZooKeeper采用过半数存活原则,Eureka采用自我保护机制解决分区问题
4.Eureka本质上是一个工程,而ZooKeeper只是一个进程
13. eureka自我保护机制是什么?
当Eureka Server 节点在短时间内丢失了过多实例的连接时节点会进入自我保护模式,保护注册信息,不再删除注册数据,故障恢复时,自动退出自我保护模式。
14. 什么是Ribbon?
ribbon是一个负载均衡客户端。feign默认集成了ribbon。
15. 什么是feigin?它的优点是什么?
1.feign采用的是基于接口的注解
2.feign整合了ribbon,具有负载均衡的能力
3.整合了Hystrix,具有熔断的能力
使用:
1.添加pom依赖。
2.启动类添加@EnableFeignClients
3.定义一个接口@FeignClient(name=“xxx”)指定调用哪个服务
16. Ribbon和Feign的区别?
1.Ribbon都是调用其他服务的,但方式不同。
2.启动类注解不同,Ribbon是@RibbonClient feign的是@EnableFeignClients
3.服务指定的位置不同,Ribbon是在@RibbonClient注解上声明,Feign则是在定义抽象方法的接口中使用@FeignClient声明。
4.调用方式不同,Ribbon需要自己构建http请求,步骤相当繁琐。Feign需要将调用的方法定义成抽象方法即可。
17. 什么是Spring Cloud Bus?
spring cloud bus 将分布式的节点用轻量的消息代理连接起来,它可以用于广播配置文件的更改或者服务直接的通讯,也可用于监控。
如果修改了配置文件,发送一次请求,所有的客户端便会重新读取配置文件。
使用:
1.添加依赖
2.配置rabbimq
18. 什么是Hystrix?
防雪崩利器,具备服务降级,服务熔断,依赖隔离,监控(Hystrix Dashboard)
服务降级:
优先核心服务,非核心服务不可用或弱可用。通过HystrixCommand注解指定。
fallbackMethod(回退函数)中具体实现降级逻辑。
19. springcloud断路器作用?
半开:短时间内 有恢复迹象 断路器会将部分请求发给该服务,正常调用时 断路器关闭
关闭:当服务一直处于正常状态 能正常调用
20. 什么是SpringCloudConfig?
在分布式系统中,由于服务数量巨多,为了方便服务配置文件统一管理,实时更新,所以需要分布式配置中心组件。在Spring Cloud中,有分布式配置中心组件spring cloud config ,它支持配置服务放在配置服务的内存中(即本地),也支持放在远程Git仓库中。在spring cloud config 组件中,分两个角色,一是config server,二是config client。
使用:
1、添加pom依赖
2、配置文件添加相关配置
3、启动类添加注解@EnableConfigServer
- @Autowired默认按byType自动装配,而@Resource默认byName自动装配。
- @Autowired只包含一个参数:required,表示是否开启自动准入,默认是true。而@Resource包含七个参数,其中最重要的两个参数是:name 和 type。
- @Autowired如果要使用byName,需要使用@Qualifier/ˈkwɒlɪfaɪə(r)/ 一起配合。而@Resource如果指定了name,则用byName自动装配,如果指定了type,则用byType自动装配。
- @Autowired能够用在:构造器、方法、参数、成员变量和注解上,而@Resource能用在:类、成员变量和方法上。
- @Autowired是spring定义的注解,而@Resource是JSR-250定义的注解。
-
Mybatis
-
1.Mybatis中一级缓存和二级缓存的区别?******* CRUD
一级缓存的作用域是在SqlSession中执行相同的SQL查询时;第一次会去查询数据库,并写在缓存中,第二次会直接从缓存中取,
二级缓存的作用域是针对mapper做缓存。
一级缓存默认是开启状态的,不需要做任何配置
sqlSession 关闭后(close) ,一级缓存的数据会保存到二级缓存中,下次相同的查询就会去二级缓存中去查询。
二级缓存开启要求:
1,xml 配置中开启 二级缓存
2,去mapper映射文件中使用二级缓存
3,需要将要存储数据的Java对象实现 Serializable[ˈsɪərɪəlaɪzəbl]接口,为了将数据取出做反序列化操作,因为二级的缓存的存储方式多种多样,有可能存储在内存中,也可能储存到磁盘中。
2. mybatis中#和$的区别是什么
①#传入的参数在SQL中显示为字符串(当成一个字符串),会对自动传入的数据加一个双引号。
select id,name,age from student where id =#{id}
上述 sql 的解析为:
select id,name,age from student where id ="1"
$传入的参数在SqL中直接显示为传入的值
select id,name,age from student where id =${id}
上述 sql 的解析为:
select id,name,age from student where id =1
②#可以防止SQL注入的风险(语句的拼接);但$无法防止Sql注入。
③$方式一般用于传入数据库对象,例如传入表名。
④大多数情况下还是经常使用#,一般能用#的就别用$;但有些情况下必须使用$,例:MyBatis排序时使用order by 动态参数时需要注意,用$而不是#。
3.mybatis怎么写
在mybatis中使用包括起来的,所以不能使用,可以使用转义字符
>> 号
<:< 号
4.mybatis常用标签
集合
-
resize() 为扩容方法
1.遍历map的几种方式
第一种遍历map的方式是通过map.keySet()的方式遍历的,这种方式主要是获取key,然后根据key获取value的值
第二种方法是基于迭代器的方式遍历的,使用map.entrySet()方法牟其中可以直接遍历到entry的key和value的值
第三种方式是直接使用Map.entrySet()遍历出key和value,这种遍历是性能较高的方法,针对map值较大的时候都有很不错的效率
第四种方法就是通过Map.values()的方法来获取所有的值,这里这种方法仅能获取值,并不能获取到原有的键,所以使用很少
2 .ArrayList和LinkList的区别?*
①ArrayList是实现了基于动态数组的数据结构,而LinkedList是基于链表的数据结构;
② 对于随机访问get和set,ArrayList要优于LinkedList,因为LinkedList要移动指针;
③ 对于添加和删除操作add和remove,LinkedList要比ArrayList快,因为ArrayList要移动数据。
3.如何保证ArrayList线程安全
①继承Arraylist,然后重写或按需求编写自己的方法,这些方法要写成synchronized,在这些synchronized的方法中调用ArrayList的方法。
② 使用Collections工具类中的Collections.synchronizedList()创建一个list
List list = Collections.synchronizedList(new ArrayList());
4.hashMap和hashTable的区别
①继承的父类不同
Hashtable继承自Dictionary类,而HashMap继承自AbstractMap类。但二者都实现了Map接口。
②线程安全性不同
Hashtable 线程安全,HashMap线程不安全
③key和value是否允许null值
hashtable中,key和value都不允许出现null值。
hashmap中,key和value允许出现null值。
④hashTable 基础长度11 加载因子 0.75 扩容2倍+1
HashMap 基础长度16 加载因子 0.75 扩容 2
5.如何保证hashMap线程安全*
①使用Collections类的synchronizedMap方法包装一下
②使用Concurrent[kənˈkʌrənt]HashMap,它使用分段锁来保证线程安全
6.list中存入一个学生对象,如何根据学生的年龄进行排序
实现Comparable[ˈkɒmpərəbl]接口,重写compareTo方法
7.默认加载因子,扩容
Class 初始大小 加载因子 扩容倍数 底层实现
ArrayList 10 1 1.5倍 Object数组 有序的 可重复
Vector 10 1 2倍 Object数组 有序的
HashSet 16 0.75f 2倍 `````````````````` HashMap 无序的 不可重
HashMap 16 0.75f 2倍 Map.Entry 无序的
Hashtable 11 0.75f 2倍+1 Hashtable.Entry数组
注:JDK1.7之前ArrayList扩容倍数是1.5+1
8.List和Set的区别*
List 有顺,可重复,存储单列数据的集合;Map 无序,其 key 不可重复,值可重复的,存储key,value键值对。
9.HashMap为什么线程不安全 ConcurrentHashMap/kənˈkʌrənt/
(1)在put的时候,因为该方法不是同步的,假如有两个线程A,B它们的put的key的hash值相同,不论是从头插入还是从尾插入,假如A获取了插入位置为x,
但是还未插入,此时B也计算出待插入位置为x,则不论AB插入的先后顺序肯定有一个会丢失;
(2)在扩容的时候,jdk1.8之前是采用头插法,当两个线程同时检测到hashmap需要扩容,在进行同时扩容的时候有可能会造成链表的循环,
主要原因就是,采用头插法,新链表与旧链表的顺序是反的,在1.8后采用尾插法就不会出现这种问题,同时1.8的链表长度如果大于8就会转变成红黑树。
而JDK1.8中,HashMap采用位桶+链表+红黑树实现,当链表长度超过阈值(8)时,将链表转换为红黑树
10.HashSet底层
HashSet是基于HashMap实现的,HashSet底层使用HashMap来保存所有元素
11.Map添加相同的key
HashMap是的key是不能重复的,如果有相同的key,最后一个key对应的value会把前一个相同的value覆盖掉。
12.ArrayList复杂度
ArrayList 是线性表(数组)get() 直接读取第几个下标,复杂度 O(1)add(E) 添加元素,直接在后面添加,复杂度O(1)add(index, E) 添加元素,在第几个元素后面插入,后面的元素需要向后移动,复杂度O(n)remove()删除元素,后面的元素需要逐个移动,复杂度O(n)
LinkedList 是链表的操作get() 获取第几个元素,依次遍历,复杂度O(n)add(E) 添加到末尾,复杂度O(1)add(index, E) 添加第几个元素后,需要先查找到第几个元素,直接指针指向操作,复杂度O(n)remove()删除元素,直接指针指向操作,复杂度O(1)
线程
-
1.线程使用场景*
2.java中创建线程的三种方法以及区别
Java使用Thread类代表线程,所有的线程对象都必须是Thread类或其子类的实例。Java可以用三种方式来创建线程,如下所示:
1)继承Thread类创建线程
2)实现Runnable接口创建线程
3)使用Callable和Future创建线程
3.run()和start()方法的区别
run(): 封装了被线程执行的代码,直接调用仅仅是普通方法的调用
start(): 启动线程,并由JVM自动调用run()方法
注:start()方法被用来启动新创建的线程,而且start()内部调用了run()方法,这和直接调用run()方法的效果不一样。当你调用run()方法的时候,只会是在原来的线程中调用,没有新的线程启动,start()方法才会启动新线程。
4.sleep()和wait()方法的区别
sleep(): 必须指时间; 不释放锁。
wait(): 可以不指定时间,也可以指定时间; 释放锁。
5.现在有线程 T1、T2 和 T3。你如何确保 T2 线程在 T1 之后执行,并且 T3 线程在 T2 之后执行?
可以用 Thread 类的 join 方法实现这一效果。
6.Callable和Future有什么区别*
1.Callable规定的方法是call(),而Runnable规定的方法是run().
2.Callable的任务执行后可返回值,而Runnable的任务是不能返回值的。
3.call()方法可抛出异常,而run()方法是不能抛出异常的。
4.运行Callable任务可拿到一个Future对象, Future表示异步计算的结果。
7.创建线程池的几种方式
1.newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
2.newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
3.newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
4.newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
8.线程池的好处
1.降低资源消耗:通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
2.提高响应速度:当任务到达时,可以不需要等待线程创建就能立即执行。
3.提高线程的可管理性:线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,监控和调优。
9.线程数过多会造成什么异常
1、线程的生命周期开销非常高
2、消耗过多的 CPU 资源
如果可运行的线程数量多于可用处理器的数量,那么有线程将会被闲置。大量空
闲的线程会占用许多内存,给垃圾回收器带来压力,而且大量的线程在竞争 CPU
资源时还将产生其他性能的开销。
3、降低稳定性
JVM 在可创建线程的数量上存在一个限制,这个限制值将随着平台的不同而不同,
并且承受着多个因素制约,包括 JVM 的启动参数、Thread 构造函数中请求栈的
大小,以及底层操作系统对线程的限制等。如果破坏了这些限制,那么可能抛出
OutOfMemoryError 异常。
10.线程同步的方法
1.synchronized关键字
public synchronized void set(){}
2、Lock
lock.lock() 加锁;lock.unlock() 释放锁。
public class Count{
Lock lock = new ReentrantLock();
public void save(){
for(int i=0;i
{ count++;
System.out.println("count:"+count);
}
lock.unlock();
}
}
3.volatile /ˈvɒlətaɪl/ 关键字
restful与设计模式
-
1.restful
- restful其实就是一套编写接口的协议,协议规定如何编写以及如何设置返回值、状态码等信息。
- 最显著的特点:
restful: 给用户一个url,根据method不同在后端做不同的处理,比如:post 创建数据、get获取数据、put和patch修改数据、delete删除数据。
no rest: 给调用者很多url,每个url代表一个功能,比如:add_user/delte_user/edit_user/
- 当然,还有协议其他的,比如:
- 版本,来控制让程序有多个版本共存的情况,版本可以放在 url、请求头(accept/自定义)、GET参数
- 状态码,200/300/400/500
- url中尽量使用名词,restful也可以称为“面向资源编程”
REST即Representational State Transfer的缩写,可译为"表现层状态转化”。REST最大的几个特点为:资源、统一接口、URI和无状态。特别符合HTTP的无状态请求。
2.设计模式
工厂模式
单例模式 Spring中依赖注入的Bean实例默认是单例的。
适配器模式 因此Spring定义了一个适配接口,使得每一种Controller有一种对应的适配器实现类,让适配器代替controller执行相应的方法。这样在扩展Controller时,只需要增加一个适配器类就完成了SpringMVC的扩展了。
装饰器模式 一种是类名中含有Wrapper
代理模式 AOP
-
Spring
-
1、Spring 的优点?
(1)spring代码简介;(2)spring的DI机制将对象之间的依赖关系交由框架处理,减低耦合性;(3)Spring提供了AOP技术,支持将一些通用任务,如安全、事务、日志、权限等进行集中式管理,从而提供更好的复用。(4)spring对于主流的应用框架提供了集成支持。
2、Spring的AOP理解:*
AOP,面向切面编程,用于将那些与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可重用的模块,这个模块被命名为“切面”(Aspect),主要作用减少系统中的重复代码,降低了模块间的耦合度,同时提高了系统的可维护性。AOP实现的关键在于 代理模式,AOP代理主要分为静态代理和动态代理。
3、Spring的IoC理解:*
(1)IOC就是控制反转,将创建对象的权利交给spring管理
(2)Spring的IOC有三种注入方式 :构造器注入、setter方法注入、根据注解注入。
4、Spring框架中的单例Beans是线程安全的么?
但实际上,大部分的Spring bean并没有可变的状态(比如Serview类和DAO类),所以在某种程度上说Spring的单例bean是线程安全的。如果你的bean有多种状态的话(比如 View Model 对象),就需要自行保证线程安全。最浅显的解决办法就是将多态bean的作用域由“singleton”变更为“prototype”。
5.Spring基于xml注入bean的几种方式:
(1)Set方法注入;(2)构造器注入:①通过index设置参数的位置;②通过type设置参数类型;(3)静态工厂注入;(4)实例工厂;
6.Spring 框架中都用到了哪些设计模式?
(1)工厂模式:BeanFactory就是简单工厂模式的体现,用来创建对象的实例;
(2)单例模式:Bean默认为单例模式。
(3)代理模式:Spring的AOP功能用到了JDK的动态代理和CGLIB字节码生成技术;
(4)模板方法:用来解决代码重复的问题。比如. RestTemplate, JmsTemplate, JpaTemplate。
(5)观察者模式:定义对象键一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知被制动更新,如Spring中listener的实现--ApplicationListener。
7.Spring通知有哪些类型?
(1)前置通知(Before advice)(2)返回后通知(After returning advice) (3)抛出异常后通知(After throwing advice)(4)后通知(After (finally) advice)(5)环绕通知(Around Advice)
-
redis
-
1.redis场景使用*
结账,防止重复提交,结算时候会生成一个唯一id,这个id会存放在redis中,并且设置失效时间,如果存在重复id那么就不进行orcale数据库操作。
2.redis是一种高级的key:value存储系统,其中value支持五种数据类型:
1.字符串(strings)
2.字符串列表(lists)
3.字符串集合(sets)
4.有序字符串集合(sorted sets)
5.哈希(hashes)
应用场景:缓存,任务队列,网站访问统计,应用排行榜。分布式集群架构中的session分离。
3.redis是单线程还是多线程*
单线程,Redis4.0之后,可以支持多线程了,但仅仅用于用于大数据量的异步删除
4.redis为什么读取速度快
1.redis是基于内存的,内存的读写速度快;
2.redis是单线程的,省去下文切换线程的时间;
3.非阻塞IO:redis使用多路复用技术,可以处理并发的连接。非阻塞IO 内部实现采用epoll,采用了epoll+自己实现的简单的事件框架。epoll中的读、写、关闭、连接都转化成了事件,然后利用epoll的多路复用特性,绝不在io上浪费一点时间。
5.redis持久化的方式*
1.RDB:是将数据保存在临时文件中,持久化数据之后,将临时文件替换上一次的持久化文件,从而达到数据恢复,RDB是间隔一段时间持久化的,在持久化之间,如果Redis服务宕机,会造成数据丢失,这种持久化方式默认是开启的
2.AOF:是将每次数据更新的指令记录下来,在数据恢复时,按照从前到后的顺序将所有指令重新执行一遍,从而达到恢复数据。
6.AOF和RDB的区别
AOF的优点是可以更高的保持数据恢复的完整性,但AOF的文件比RDB大很多,且恢复速度慢,默认是不开启的
使用RDB持久化,Redis服务宕机,会造成数据丢失默认开启
AOF文件存储体积较大,且恢复速度慢
利用RDB实现数据持久化会使redis性能降低
如能承受数分钟以内的数据丢失,且追求大数据集的恢复速度,使用RDB
-
springmvc
-
1.springmvc执行流程*
1、 用户发送请求至前端控制器。
2、 前段控制器收到请求调用处理器映射器。
3、 处理器映射器找到具体的处理器,生成处理器对象,返回给前段控制器。
4、 前段控制器调用处理器适配器。
5、 处理适配器经过适配调用具体的contorller。
6、 Controller执行完成返回ModelAndView。
7、 处理适配器将controller执行结果ModelAndView返回给前段控制器。
8、 前段控制器将ModelAndView传给视图解析器。
9、 视图解析器解析后返回具体View。
10、前段控制器根据View进行渲染视图(即将模型数据填充至视图中)。
11、 前端控制器响应用户。
前段控制器:DispatcherServlet
处理器映射器:HandlerMapping
处理器适配器:HandlerAdapter
具体的处理器:Controller,也叫后端控制器
视图解析器:ViewReslover
2.什么是Spring MVC ?简单介绍下你对springMVC的理解?*
通过把Model,View,Controller分离,将web层进行职责解耦,把复杂的web应用分成逻辑清晰的几部分,简化开发,减少出错,方便组内开发人员之间的配合。
3.Springmvc的优点:
(1)可以支持各种视图技术,而不仅仅局限于JSP;
(2)与Spring框架集成(如IoC容器、AOP等);
(3)清晰的角色分配:前端控制器(dispatcherServlet) , 请求到处理器映射(handlerMapping), 处理器适配器(HandlerAdapter), 视图解析器(ViewResolver)。
(4) 支持各种请求资源的映射策略。
4.SpringMVC怎么样设定重定向和转发的
(1)转发:在返回值前面加"forward:"
(2)重定向:在返回值前面加"redirect:"
5、SpingMvc中的控制器的注解一般用那个,有没有别的注解可以替代?
答:一般用@Controller注解,也可以使用@RestController,@RestController注解相当于@ResponseBody + @Controller,表示是表现层,除此之外,一般不用别的注解代替。
6、SpringMvc用什么对象从后台向前台传递数据的?
答:通过ModelMap对象,可以在这个对象里面调用put方法,把对象加到里面,前台就可以通过el表达式拿到。
7.接受参数注解
@RequestParam
@RequestBody
-
springCloud
-
1. 什么是 spring cloud?
利用 spring boot 的开发便利性巧妙地简化了分布式系统的开发,如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等,都可以用 spring boot 的开发风格做到一键启动和部署。
2. spring cloud 断路器的作用是什么?
当某个服务单元发生故障之后,通过断路器的故障监控,向调用方返回一个错误响应,而不是长时间的等待。
3. spring cloud 的核心组件有哪些?
Eureka:服务注册于发现。
Feign:基于动态代理机制,根据注解和选择的机器,拼接请求 url 地址,发起请求。
Ribbon:实现负载均衡,从一个服务的多台机器中选择一台。
Hystrix:提供线程池,不同的服务走不同的线程池,实现了不同服务调用的隔离,避免了服务雪崩的问题。
Zuul:网关管理,由 Zuul 网关转发请求给对应的服务。
4. SpringCloud和Dubbo
SpringCloud和Dubbo都是现在主流的微服务架构
SpringCloud是Apache旗下的Spring体系下的微服务解决方案
Dubbo是阿里系的分布式服务治理框架
5. SpringBoot和SpringCloud
SpringBoot专注于快速方便的开发单个个体的微服务
SpringCloud是关注全局的微服务协调整理治理框架,整合管理各个微服务,为各个微服务之间提供,配置管理,服务发现,断路器,路由,事件总线等集成服务
SpringBoot不依赖于SpringCloud,SpringCloud依赖于SpringBoot,属于依赖关系
SpringBoot专注于快速,方便的开发单个的微服务个体,SpringCloud关注全局的服务治理框架
6. 微服务之间是如何独立通讯的
1.远程过程调用(Remote Procedure Invocation):
优点: 简单,常见,因为没有中间件代理,系统更简单
缺点:只支持请求/响应的模式,不支持别的,比如通知、请求/异步响应、发布/订阅、发布/异步响应降低了可用性
2.消息:
使用异步消息来做服务间通信。服务间通过消息管道来交换消息,从而通信。
优点:
把客户端和服务端解耦,更松耦合提高可用性,因为消息中间件缓存了消息,直到消费者可以消费支持很多通信机制比如通知、请求/异步响应、发布/订阅、发布/异步响应
缺点:
消息中间件有额外的复杂
7. 负载均衡的意义是什么?
负载均衡旨在优化资源使用,最小响应时间并避免任何单一资源的过载。
8. springcloud如何实现服务的注册?
1.服务发布时,指定对应的服务名,将服务注册到 注册中心(eureka zookeeper)
2.注册中心加@EnableEurekaServer,服务用@EnableDiscoveryClient,然后用ribbon或feign进行服务直接的调用发现。
9. 什么是服务熔断?什么是服务降级
服务熔断指的是某个服务故障或异常直接熔断整个服务,而不是一直等到此服务超时。
通过维护一个自己的线程池,当线程达到临界值的时候就启动服务降级,如果其他请求继续访问就直接返回fallback的默认值
10. 微服务的优缺点分别是什么?说下你在项目开发中碰到的坑
优点
- 代码易理解
- 开发效率提高,一个服务只做一件事
- 微服务可以被很少人单独开发
- 微服务是松耦合的
- 可以用不同的语言开发,面向接口编程
- 易于与第三方集成
- 多服务维护,加大运维量
- 系统部署依赖要求性严谨
- 服务间通信成本高
- 需要保持个个微服务之间的数据一致性
- 维度(springcloud)
- 服务开发:springboot spring springmvc
- 服务配置与管理:Netfix公司的Archaiusm ,阿里的Diamond
- 服务注册与发现:Eureka,Zookeeper
- 服务调用:Rest RPC gRpc
- 服务熔断器:Hystrix
- 服务负载均衡:Ribbon Nginx
- 服务接口调用:Fegin
- 消息队列:Kafka Rabbitmq activemq
- 服务配置中心管理:SpringCloudConfig
- 服务路由(API网关)Zuul
- 事件消息总线:SpringCloud Bus
更多推荐
三年工作经验java面试宝典(个人总结,现分享)
发布评论