赞
踩
一.什么是面向对象?
是基于面向过程而言,面向对象是将功能通过对象来实现,将功能封装进对象之中,让对象去实现具体的细节。
二.标识符的格式?
1.可以使用字母、数字、_、$来组成,不能使用特殊符号.
2.命名要做到见名识意,不能以数字开头.
3.不能使用关键字来作为标识符.
4.标识符命名严格区分大小写.
三.面向对象的特征?
1.封装
将数据和过程包裹起来,通常通过private来修饰属性和方法,封装后需要提供对外公共操作的方式。
2.继承
从父类中派生出一种新类(子类),子类继承父类中的属性和方法,如果对父类的属性和方法不满意,可以进行对其重写操作。
3.多态
包含了封装和继承操作,通常父类对象直接指向子类对象,一个类可以实现多种状态,具有灵活,共享的优势.
(向上造型):把子类对象统一看作父类对象
(向下造型):把看作父类对象的子类对象重新还原成子类对象
四.拦截器和过滤器的区别
相同:
1.功能类似,都是对请求进行拦截过滤
2.都可以形成链,即拦截链与过滤链,顺序由配置决定
不同:
1.所属框架不同
过滤器是JavaEE的组件,拦截器是SpringMVC的组件
2.发动时机不同
过滤器是在Servlet到达之前执行,拦截器是在Servlet到达之后,Controller到达之前执行
3.方法数量不同
过滤器只有doFilter方法,拦截器有postHandle(请求在Servlet之后,视图渲染之前执行),preHandle(请求到达Servlet之前执行),afterHandle(请求结束之前执行,用于释放资源)3种方法
4.名单不同
过滤器配置的是黑名单,拦截器白/黑名单都可以配置
五、String、StringBuffer和StringBuilder
String:创建之后的字符串是不可变,每次进行拼接新字符串时都会产生新的对象,不仅效率低而且会浪费大量内存资源
StringBuffer:是可变的和线程安全的字符串操作类(多线程操作字符串),操作时不会产生新的对象,有一定的缓冲区容量,当超过该容量时会进行自动扩容
StringBuilder:是可变的和线程不安全的字符串操作类,功能和StringBuffer类似,比起Buffer它的速度更快(单线程操作字符串)
六、线程池及其优点
线程池:能够容纳多个线程的容器,里面的线程可以反复使用,省去了频繁创建线程对象的操作,避免了过多的资源占用
1.降低资源消耗
2.提高响应速度
3.提高线程的可管理性
七.Static的用法
1.静态方法
不能使用this,不能被对象调用
2.静态变量
被所有对象所共享,在内存中只有一个副本
3.静态构造函数
只会在类加载时执行一次
4.静态内部类
直接访问外部类的属性
八.重写与重载的区别
1.重载:同一类中方法名相同但参数列表不同
2.重写:子类的方法名/参数列表和父类相同(子类对父类的属性或方法不满意而重写父类方法)
一大:子类修饰符范围>=父类修饰符范围
两同:方法名相同 参数列表相同
两小:子类异常类型<=父类异常类型 子类返回值类型<=父类返回值类型
九.同步与异步的区别
线程:
同步:多线程并发执行,一个线程必须等待另一个线程执行结束,才能执行
异步:多线程并发执行,一个线程无需等待另一个线程执行结束,即可执行
请求:
同步:客户端发起的请求必须等待前一个请求结束才能发起
异步:客户端发起的请求无需等待前一个请求结束即可发起
十.重定向与转发的区别
重定向:是一种客户端行为,浏览器向服务器发送一个请求并收到响应后再次向一个新地址发出请求,重定向一般至少请求两次,并且它的地址栏会发生变化,可以跳转到任意URL地址,重定向无法进行数据的共享.
转发:是一种服务器端行为,服务器收到请求后为了完成响应跳转到一个新的地址,转发只请求一次,转发的地址栏不会发生变化,转发只能跳转本站点资源,可以实现数据的共享;
十一.事务是什么,有什么特性
事务:是数据库执行操作的最小执行单位,不可在分,即一个事务的操作要么全部成功,要么全部失败
ACID:
原子性:事务是执行操作的最小单位,不可再分
一致性:从一个正确的状态到另一个正确的状态
隔离性:多个事务并发时,事务之间相互独立,互不干扰
持久性:数据提交后,数据在数据库中的改变是永久的
十二.事务的隔离级别
1.事务并发时的3大异常
脏读:事务a读取了事务b提交前的数据库
不可重复读:事务a在事务b修改前读取的数据和在修改后读取的数据不相同
幻读:事务a执行操作时,事务b进行了增/删操作,事务a读取的数据不同
2.4大隔离级别
读未提交:数据未提交前的数据对外可见,隔离级别最低,不可避免。。。
读已提交:数据提交后的数据对外可见,可避免脏读
可重复读:对访问的数据进行加锁(排它锁),查询数据时就会加锁,可避免不可重复读和脏读
串行:最高隔离级别,避免脏读,幻读,不可重复读
十三.什么是SQL注入,如何防止SQL注入
由于没有使用预编译,在前端输入的数据会拼接上SQL语句(加上#或者’使后面的语句被注释等),使得被拼接的语句被执行,非法获取数据库中的数据。
加上预编译或者占位符,对输入数据进行长度校验或者占位独立移植
十四.乐观锁与悲观锁
乐观锁:事务A总是乐观的认为,自己访问数据期间,其他事务不会去操作数据,所以可以多事务并发访问执行,但并发执行容易造成数据安全问题,因此为了保证数据的安全,使用Version机制
悲观锁:事务A总是悲观的认为,自己访问期间,其他事务会参与并发数据操作,为了保证数据的安全,会加上一个排它锁,其他事务无法访问
List:有序可以重复的集合
ArrayList:底层的数据结构为数组,查询操作的性能高,增删操作的性能比较低,根据下标进行操作,调用add初始化容量为10、扩容时每次都将扩容1.5倍,同时原值添加到新数组中,提供了Iterator方法增强迭代能力.
LinkedList:底层的数据结构为双向链表,增删的性能高,查询的性能比较低,根据首尾节点进行操作
Set:无序不可重复集合
HashSet:无序的
TreeSet:底层采用红黑树的数据结构进行了排序
Queue:代表先进先出的队列
Map:键值对
HashMap:没有sysnchronzied来修饰,是非线程安全的,key和value可以用null表示
底层实现:数组+链表
1.jdk8后,链表长度超过8,并且数组长度超过64时会变成红黑树,长度低于6时又转变成链表
2.计算key的hash值,二次hash后对数据进行取模,对应到数组下标
3.如果产生hash冲突,先进行equals比较,相同则取代该元素
TreeMap:实现了排序
Collection:一个接口
Collections:一个操作接口的类
十六.break,continue,return的区别
break:跳出当前整个循环,到外层的代码进行去执行
continue:跳出本次循环,下一个迭代继续运行循环,内层循环运行完后,外层继续执行
return:直接返回函数,所有的代码(包括循环体)都不再执行
十七:单例的懒汉式与饿汉式
- //懒汉式:先不创建对象,只有当页面需要对象时才创建对象(延迟加载的思想)
- public class Sinleton{
- private volatile static Singleton singleton; //volatile用于确保先行关系
- private Singleton(){}
- private static Singleton getInstance(){
- if(singleton==null){
- synchronzied(Sinleton.class){
- if(singleton==null){
- singleton=new Singleton();
- }
- }
- }
- }
- return singleton;
- }
- //饿汉式:不管页面需不需要对象,都会创建对象
- public class Singleton{
- private static Singleton singleton=new Singleton();
- private Singleton(){}
- private static Singleton getInstance(){
- return singleton;
- }
- }
十八.什么是反射?
在运行状态中,对于任意一个类都能知道它的所有属性和方法,对于任意一个对象都能调用它的任意方法和属性,这种动态获取信息及调用对象方法的功能称为反射。
缺点是破坏了封装性以及泛型约束。
反射是框架的核心,Spring 大量使用反射。
创建方法:
Class<?> student1=Class.forName("路径");
Class<?> student2=Student.class;
Class<?> student3=new Student().getClass();
十九.内存溢出与内存泄漏?
内存溢出:JVM的剩余内存不足以分配给请求的资源.
内存泄漏:JVM分配出去的内存回收不回来,内存泄漏若持续累积将造成内存溢出.
二十.Session与Cookie的区别?
1.作用位置不同?
Session的数据保存在服务端中,Cookie的数据保存在客户端中.
2.有效期不同?
Session的有效期是从闲置开始的30分钟,而Cookie的默认生命周期是一次会话,当浏览器关闭时,Cookie销毁,Session保存在Cookie中的SessionId随之消失,此时Session开始闲置.
3.保存的数据类型不同?
Session可以保存任意类型的数据类型
Cookie只能保存字符串的数据类型
4.保存的数据量不同?
Session保存的数据量没有限制
Cookie最大只能保存4k的数据量
二十一.抽象类与接口的区别?
成员变量:
抽象类没有要求,接口默认为public static final 常量
构造方法:
抽象类有构造方法,不能实例化,接口没有构造方法,不能实例化
方法:
抽象类可以没有抽象方法,但有抽象方法的类一定是抽象类,接口默认为public abstract
继承:
抽象类为单继承,接口为多继承
二十二.Mybatis中${}和#{}的区别
${}:该占位符只用于字符串拼接,没有采用预编译
#{}:该占位符用于传参,采用了预编译,执行时将其替换成?
补充:mybatis的三大执行器?
SimpleExecutor: 默认的执行器, 对每条sql进行预编译->设置参数->执行等操作
BatchExecutor: 批量执行器, 对相同sql进行一次预编译, 然后设置参数, 最后统一执行操作
ReuseExecutor: 重用执行器会重用预处理语句(prepared statements)
二十三.SpringMVC的5大组件以及请求流程
5大组件:
DispatcherServlet : 前端控制器
HandlerMapping : 映射器
Controller : 控制器
ModelAndView : 数据模型与视图
ViewResolver : 视图解析器
请求流程:
DispatcherServlet接收到请求--->经过HandlerMapping的解析--->请求到达对应的Controller--->
Controller处理后返回ModelAndView给DispatcherServlet--->在DispatcherServlet视图渲染之前,
ViewResolver对视图进行解析--->渲染视图
二十四.自动装配Resource注解和Autowired注解的区别
自动装配原理:Spring Boot通过@EnableAutoConfiguration注解开启自动配置,加载spring.factories中注册的各种AutoConfiguration类,当某个AutoConfiguration类满足其注解@Conditional指定的生效条件时,实例化该AutoConfiguration类中定义的Bean(组件等),并注入Spring容器,就可以完成依赖框架的自动配置。
1.所属框架不同
@Resource是JavaEE提供的
@Autowired是Spring框架提供的
2.装配类型不同
@Resource默认按照name进行装配/注入,若找不到name,则自动按照Type进行装配/注入
@Autowired默认按照Type进行装配/注入
二十五:Mybatis里一级缓存与二级缓存
一级缓存:是sqlSession级别的缓存,默认开启,每个事务具有对应的一级缓存
1.事务查询数据时会先从缓存中去查,查到了直接返回,查不到,则去数据库进行查找,查到的数据立即缓存到一级缓存里
2.事务进行更新数据时,该事务的一级缓存将清空,以确保缓存的准确性
二级缓存:是namespace/mapper级别的缓存,默认关闭,可通过配置开启
1.事务A从mapper中查询的数据会缓存到mapper的二级缓存中,事务B再从mapper中查询数据时会先从二级缓存中找,有则返回,无则先去一级缓存中找,没有就去数据库中查询
2.若多个事务对mapper进行操作,如果其中一个事务进行更新操作,那么为了保证数据的准确性,二级缓存会被清空
二十六.Ribbon和Feign
区别:
1.Ribbon向其他服务发起请求时需要构建http请求(请求方式:restTemplate.getForObject)
2.Feign向其他服务发起请求时无需手动构建http请求,对Ribbon进行了再次封装,通过声明式接口调用业务方法即可实现访问其他服务
使用Feign的步骤
1.导入依赖
2.在启动类上加@EnableFeignClients的注解
3.在业务层上加上@FeignClient注解定义对应要访问的服务,通过在控制层中注入service对象即可访问其他服务
二十七:什么是死锁,死锁的危害
死锁:两个或两个以上的进程/线程进行资源的争夺而造成的一种互相等待现象,若无外力作用,它们将无法推进下去
危害:
1.资源的利用率会降低
2.进程得到错误的结果
3.还会导致产生更多的死锁
必要条件:
1 互斥条件: 一个资源每次只能被一个线程使用
2 请求和保持条件: 一个线程在阻塞等待某个资源时,不释放已占有资源
3 不剥夺条件: 一个线程已经获得的资源,在未使用完之前,不能被强行剥夺
4 环路等待条件: 若干线程形成头尾相接的循环等待资源关系 这是造成死锁必须要达到的4个条件,如果要避免死锁,只需要不满足其中某一个条件即可。而其中前3个条件是作为锁要符合的条件,所以要避免死锁就需要打破第4个条件,不出现循环等待锁的关系.
二十八:对象创建的过程
1.检查加载
检查这个指令的参数是否能在常量池中定位到一个类的符号引用
2.分配内存
为新生对象分配内存
3.内存空间初始化
将分配到的内存空间都初始化为零值
4.设置
设置存放在对象头的hash码,对象的GC分代年龄等信息
5.对象初始化
二十九:volatile有啥特性和原理
1.保证变量对所有线程可见
当一条线程修改了变量值,新值对于其他线程来说是立即可以得知的
2.禁止指令重排序优化
使用volatile变量进行写操作,汇编指令带有lock前缀,相当于一个内存屏障,后面的指令不能重排到内存屏障之前
三十:泛型
泛型:即参数化类型,一般用于三种方式:泛型类,泛型接口,泛型方法
泛型类:通常完成一组类的操作对外开放相同的结果
class 类名称 <泛型标识>{ private 泛型标识 /*(成员变量类型)*/ 成员变量;
泛型接口:与泛型类的功能基本相同,通常用于各种类的生产器中
泛型方法:泛型方法独立于类而产出变换
三十一:异常
1.所有的异常都来自顶级父类Throwable,Exception和Error为它的子类
2.Error是程序无法处理的错误,一旦出现该错误,程序被迫停止
3.Exception不会导致程序停止,分为RuntimeException运行时异常和CheckedException编译时异常,RuntimeException发生在程序运行过程中,会导致程序当前线程执行失败,CheckedException常常发生在编译过程中,会导致编译不通过.
三十二:如何实现一个ioc容器
1.配置文件包扫描路径
2.递归包扫描获取.class文件
3.反射确定需要交给ioc的类
4.对需要进行注入的类进行依赖注入
三十三:双亲委派模型
向上委派:查找缓存是否加载该类,有则直接返回,无则继续向上
向下委派:查找加载路径,有则加载返回,无则继续向下
好处:
1.为了安全性,避免用户自己编写的类动态替换了java的一些核心类
2.避免了重复加载(相同的.class文件被不同的Classload文件加载就是不同的类)
三十四:Spring,SpringBoot,SpringMVC的区别
Spring是一个轻量级的IOC、DI和AOP的容器框架,可以用来装javabean对象,中间层框架可以起一个连接的作用,使开发更快更敏捷
SpringMVC是spring对web框架的一个解决方案....后续见mvc的过程
SpringBoot是spring提供的一种快速开发工具包,简化了配置,整合了一系列的解决方案,开箱即用,便于程序员快速的开发应用
三十五.Spring 3大核心技术
IOC:控制反转,将对象的创建权交给Spring进行管理,强调的是现象结果
初始化:
1.直接将注解Bean注册到容器中,可以在初始化容器时注册,也可以在容器创建之后手动注册,然后刷新容器使其对注册的注解Bean进行处理
2.通过扫描指定的包及其子包的所有类处理,在初始化注解容器使指定要自动扫描的路径
实现:
1.配置文件包扫描路径
2.递归包扫描获取.class文件
3.反射确定需要交给ioc的类
4.对需要进行注入的类进行依赖注入
DI:依赖注入,容器动态的将某个依赖关系注入到组件中,强调的是实现过程
实现方式:
1.构造方法注入:IOC会检查被注入对象的构造方法,取得它所需要的依赖对象列表,进而为其注入相应的对象
2.setter方法注入:当前对象只需要为其依赖对应的属性添加setter方法,就可以通过setter方法将依赖对象注入到被依赖对象中。
3.接口注入:必须实现某个接口,接口提供方法来为其注入依赖对象.
AOP:面向切面编程,是一种编程思想,预编译方式和运行期动态代理的方式实现不修改源代码的情况下给程序动态统一添加功能的技术,通过将程序中的交叉业务逻辑封装成一个切面,注入到目标对象中,用于将业务代码和通用功能代码实现分离解耦,简单的说就是将代码中重复的部分抽取出来,在需要执行的时候使用动态代理机制,在不修改源码的基础上对方法进行增强,以提高代码的可维护性和可扩展性
AOP的实现:通过动态代理机制实现
动态代理:
1.JDK动态代理:使用jdk的反射api产生代理对象,为实现接口生成代理对象
2.CGLIB动态代理:先导入cglib资源库才能使用(spingboot2.x版本后都使用cglib),为类对象生成代理对象
三十六.Redis的5种数据类型
String(字符串):底层是一个简单动态字符串,支持扩容,存储字符串,可以保存高热度数据 ----点击量
实现:点击一下,触发命令:incr key
Hash(哈希):存储的是键值对,适合保存对象数据
优点:可以直接操作field-value
List(列表):存储线性有序且可重复的元素,底层数据结构可以是双向链表/压缩列表
获取元素:根据key获取list列表的数据,通过index获取list的数据值
应用场景:微信点赞
Set(集合):存储不可重复的元素,一般用于求交集、差集等,底层数据结构可以是hash和整数数组
应用场景:黑名单
zset(有序集合):
1.保存不重复的字符串实现排序
2.存入字符串时需要为每个字符串关联score,根据score实现排序
3.sorted set中的score可能相同
4.若存入的字符串已经存在,则后面的score覆盖前面的score
应用场景:电影排行
三十七.Redis的穿透与雪崩与击穿
穿透:
当业务自身代码、数据出现问题或者一些恶意攻击、爬虫造成了大量空的命中,而缓存系统通过key进行查询,如果value不存在就会去db中查询数据,此时请求的并发量很大的话就会给db造成的压力.
解决方案:
1.设置布隆过滤器,将所有可能存在的数据移入BitMap,一定不存在的数据会被拦截到
2.依旧将查询到的空数据进行缓存,但是会将过期时间设置的很短
雪崩:
缓存承接着大量的请求,保护着存储层,当缓存服务器重启或者大量缓存集中在某时间段失效,整体不能够提供服务.这时所有的请求到达存储层,以致存储层调用量暴增,使得存储层瘫痪.
解决方案:
1.设置redis集群和db集群的高可用,如果redis宕机,可以由其他机器立即来代替
2.使用互斥锁,当缓存失效后,通过加锁或者队列的方式来控制读写数据的线程数量
3.不同的key设置不同的过期时间,避免在同一时间段失效
4.设置永远不过期
5.使用hystrix,隔离各种资源的线程池,从而保护主线程池
击穿:
缓存中没有但数据库有的数据,这时由于并发用户特别多,读缓存没有读到数据的同时有跑到数据库去取数据,这时数据库压力瞬间增大
解决方案:
1.使用热点数据永远不过期
2.加互斥锁
三十八:Redis中的持久化策略RDB和AOF
RDB(Redis DataBase):在指定的时间间隔内将内存的数据集快照写入磁盘,实际操作过程是fork一个子进程,先将数据集写入临时文件,写入成功后,在替换之前的文件,用二进制压缩存储。
优点:
1.整个Redis数据库将只包含一个文件dump.rdb,方便持久化
2.容灾性好,方便备份
3.性能最大化,使用单点子进程来进行持久化,主进程不会进行任何IO操作,保证了redis的高效能
4.相对于数据集大时,比AOF的启动效率更高
缺点:
1.数据安全性低(持久化之间redis发生故障会发生数据丢失)
2.由于通过fork子进程来协助完成数据持久化工作,数据量大时,停顿时间会比较长
AOF(Append Only File):以日志的形式记录服务器所处理的每一个写、删除操作,查询操作不会记录,以文本的方式记录,可以打开文件看到详细的操作记录
优点:
1.数据安全,Redis提供了3种同步策略,即每秒同步、每修改同步和不同步。
2.通过append模式写文件,即使中途服务器宕机也不会破坏已经存在的内容
3.AOF机制的rewrite模式
缺点:
1.AOF文件比RDB文件大,且恢复速度慢
2.数据集大的时候,比rdb启动效率低
3.运行效率没有RDB高
三十九:Redis单线程快的原因
1.纯内存操作
2.核心是基于非阻塞的IO多路复用机制
3.单线程反而避免了多线程的频繁上下文切换带来的性能问题
四十:线程的状态和过程
1.新建状态(New):新创建一个线程对象
2.就绪状态(Runable):等待其他线程调用改对象的start()方法,以获取CPU的使用权
3.运行状态(Running):就绪状态的线程获取了CPU,执行程序代码
4.阻塞状态(Blocked):阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行,直到线程进入就绪状态才有机会转入运行状态.
5.死亡状态:线程执行完了或者因异常退出了run方法,该线程结束生命周期
阻塞的3种状态:
1.等待阻塞:运行的线程执行wait方法,该线程会释放占用的所有资源,JVM会把线程放入等待池中,进入此状态不能被唤醒,需要其他线程调用notify或notifyAll方法才能被唤醒
2.同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则jvm会把线程放入锁池中.
3.其他阻塞:运行的线程执行sleep或join方法,或者发出i/o请求时,jvm会把该线程置为阻塞状态,当sleep状态超时,join等待线程终止或者超时,或者i/o处理完毕时,线程重新转入就绪状态
四十一:sleep(),yield(),join(),wait()的区别
yield():执行后线程直接进入就绪状态,马上释放CPU的执行权,但是依然保留了CPU的执行资格
join():执行后线程进入阻塞状态
sleep()和wait()的异同
1.sleep是Thread类的静态本地方法,wait则是Object类的本地方法
2.sleep方法不会释放lock,wait会释放,并且加入到等待队列中
3.sleep等待不依赖于synchronzied,但wait依赖
4.sleep不需要被唤醒,wait需要
5.sleep一般用于单线程休眠或轮询,wait用于多线程之间的通信
6.sleep会让CPU执行时间强制上下文切换,wait不一定
四十二:线程安全
概念:当多个线程访问一个对象时,如果不用进行额外的同步控制或其他的协调操作,调用这个对象的行为都可以获得结果,那么这个线程就是安全的
栈:每个线程独有的,保存其运行状态和局部自动变量的,栈在线程开始的时候初始化,每个线程的栈互相独立,因此栈是线程安全的
堆:进程和线程共有的空间,操作时对进程初始化的时候分配,运行过程中也可以向系统要额外的堆,用完后归还
线程安全的集合: Collections、java.util.concurrent (JUC)
如何保证线程安全
概念:多线程背景下,线程没有按照我们的预期执行,导致操作共享变量出现异常
1.原子类
通过CAS比较与交换的机制实现线程安全的更新共享变量。通过预期值与内存值的比较来判断是否修改
2.volatile关键字
实现了变量的可见性、防止指令重排序。保证了【单个变量】读写的线程安全
3.锁
可以保证临界区内的多个共享变量线程安全。
java中常用的锁有两种:synchronized+lock锁。synchronized锁是互斥锁,可以作用于实例方法、静态方法、代码块,基于对象头和Monitor对象,在1.6之后引入轻量级锁、偏向锁等优化。lock锁接口可以通过lock、unlock方法锁住一段代码,基于AQS实现,其加锁解锁就是操作AQS的state变量,并且将阻塞队列存在AQS的双向队列中。
四十三:守护线程
守护线程:为所有非守护线程提供服务的线程,依赖于整个进程而运行,当其他线程结束,程序结束,守护线程中断
作用:
比如GC垃圾回收线程,当我们不再有任何运行的Thread,程序就不会产生垃圾,垃圾回收器也就无事可做,此时垃圾回收线程会自动离开
注意:
1.Thread.setDaemon()必须在Thread.start()之前调用,否则运行时会抛出异常
2.守护线程是为其他线程提供服务,如果全部的User Thread已经结束,守护线程没有可服务的线程,Jvm关闭
四十四:ThreadLocal
每个Thread对象都含有一个ThreadLocalMap类型的成员变量threadlocals,它存储本线程中所有的ThreadLocal对象及其值
执行set方法时,ThreadLocal首先获取当前线程对象,然后获取当前线程的ThreadLocalMap对象,再以当前ThreadLocal对象为key,将值存储进ThreadLocalMap对象中
get方法和set的方法差不多,get最后将key获取对应的value
四十五:串行,并行,并发的区别
串行:时间上不发生重叠,前一个任务没搞定,下一个任务就只能等着
并行:时间上是重叠的,两个任务在同一时刻互不干扰的痛死执行
并发:两个任务交替执行,同一时间只有一个任务在执行
四十六:索引
索引是一种排好序的快速查找的数据结构,它帮助数据库高效的进行数据的检索。在数据之外,数据库系统还维护着满足特定查找算法的数据结构(额外的存储空间),这些数据结构以某种方式指向数据,这样就可以在这些数据结构上实现高效的查找算法。
命令:create index 索引名字 on 表名(字段名) --创建索引 加Unique就是唯一索引
show index from 索引 --显示索引
create index 索引名 on 表名 (字段1, 字段2) --创建复合索引
alter table 表 drop index 表 --删除索引
分类:
单值索引:一个索引只包括一个列,一个表可以有多个列
唯一索引:索引列的值必须唯一,但允许有空值;主键会自动创建唯一索引
复合索引:一个索引同时包括多列
过程:
1.把创建索引的列的内容进行排序
2.对排序结果生成倒排表
3.在倒排表内容上拼上数据地址链
4.在查询的时候,先拿到倒排表内容,再取出数据地址链,从而拿到具体数据
聚簇索引和非聚簇索引的区别
聚簇索引和非聚簇索引最大的区别是数据域是否和索引项是否分离。聚簇索引一般采用数据表中的具有唯一性的字段(primary,unique,rowid)作为索引采用b+树结构,在叶子节点存储具体的数据,所以其找到的索引也就找到了具体的数据。而非聚簇索引数据域和索引项是分离的,它的b+树叶子节点存储的是其数据对应的主键值,获取到该主键值后再回表进入聚簇索引中查找具体的数据。一个表中只能有一个聚簇索引,但是可以有多个非聚簇索引。
B树和B+树的区别
B树
1.节点排序
2.—个节点了可以存多个元素,多个元素也排序了
B+树的特点:
1.拥有B树的特点
2.叶子节点之间有指针
3.非叶子节点上的元素在叶子节点上都冗余了,也就是叶子节点中存储了所有的元素,并且排好顺序
Mysql索引(使用的是B+树,因为索引是用来加快查询的,而B+树j通过对数据进行排序所以是可以提高查询速度的,然后通过一个节点中可以存储多个元素,从而可以使得B+树的高度不会太高,在Mysq中一个nodb页就是一个B+树节点,一个nnodb页默认16kb,所以一般情况下一繁两层的B+树可以存2.0万行左右的数据,然后通过利用B +树如t子节点存储了所有数据并且进行了排序,并且叶子节点之间有指针,可以很好的支持全表扫描,范围查找等SQL语句。
区别:
四十七:CAS
表示比较与交换,需要三个操作数,分别是内存位置V,旧的预期值A和准备设置的新值B.CAS指令执行时,当且仅当V符合A时,处理器才会用B更新V的值,否则它就不执行更新,但不管是否更新都会返回V的旧值,这些处理过程是原子操作,执行期间不会被其他线程打断.
问题:
ABA问题:如果V初次读取时是A,并且在准备赋值时仍为A,这依旧不能说明它没有被其他线程更改过,因为这段时间内假设它的值先改为B又改回A,那么CAS操作就会误认为它从来没有被改变过.
使用地方:
原子类:以AtomicInteger为例,它的内部提供了诸多原子操作的方法采用CAS指令来实现
AQS:在向同步队列的尾部追加节点时,它首先会以CAS的方式尝试一次,如果失败则进入自旋状态,并反复以CAS的方式进行尝试。
并发容器:对于并发容器,以ConcurrentHashMap为例,它的内部多次使用了CAS操作。在初始化数组时,它会以CAS的方式修改初始化状态,避免多个线程同时进行初始化。
四十八:Lock接口是啥,对比synchronzied有什么优点:
区别:
1.使用方式:synchronized关键字可以作用在静态方法、实例方法和代码块上,需要依赖Monitor(同步监视器)来实现线程通信,Lock接口是显式锁,我们需要调用其内部定义的方法显式地加锁和解锁
2.功能特性:synchronized是早期的API,Lock则是在JDK 1.5时引入的。在设计上,Lock弥补了synchronized的不足,增加了一些特性(可中断/非阻塞/可超时获取锁)
3.实现机制:synchronized的底层是采用Java对象头来存储锁信息的,对象头包含三部分,分别是Mark Word、Class Metadata Address、Array length. AQS是队列同步器,是用来构建锁的基础框架,Lock实现类都是基于AQS实现的。
lock:比同步方法和同步块提供了更具扩展性的锁操作
优点:
lock是synchronzied的扩展版,提供了无条件的,可轮询的(trylock),定时的,可中断的,可多条件队列的锁操作,另外lock的实现类基本都支持非公平锁和公平锁,synchronzied只支持非公平锁
四十九:类加载
JVM把描述类的数据从Class文件加载到内存,并对数据进行校验、解析和初始化,最终形成可以被虚拟机直接使用的Java类型
五十:什么是类加载器,有哪些
整个类的加载任务非常繁重,对类进行(加载,验证,准备,解析,初始化)
Bootstrap ClassLoader:
核心类库加载器,任何类的加载行为,都要经它过问
Extention ClassLoader:
扩展类加载器,用于加载lib目录下的jar包和.class文件
Application ClassLoader:
默认加载器,加载classpath下的其他所有jar包和.class文件
Custom ClassLoader:
自定义加载器,支持个性化的扩展功能
五十一:GC如何判断对象可以被回收
引用计数法:每个对象有一个引用计数属性,新增一个引用时计数加1,引用释放时计数减1,计数为0时可以回收.
可达性分析法:从GC Roots开始向下搜索,搜索走过的路径称为引用链,当一个对象到到GC Roots没有任何引用链相连时,则证明此对象是不可用的,这时虚拟机将其判断为可回收对象.
GC Roots的对象有:
1.虚拟机栈引用的对象
2.方法区中类静态属性引用的对象
3.方法区中常量引用的属性
4.本地方法栈中Native方法引用的属性
1. 类加载子系统,可以根据指定的全限定名来载入类或接口。
2. 执行引擎,负责执行那些包含在被载入类的方法中的指令。
3.运行时数据区
虚拟机栈:在jvm运行过程中存储当前线程运行方法所需的数据,指令,返回地址
本地方法栈:本地方法是和虚拟机非常相似的一个区域,它服务的对象是native方法
程序计数器:主要用来记录各个线程执行的字节码的地址
方法区:JDK1.7及之前是"永久代",JDK1.8以后就是"元空间",存放类的信息,常量池,方法数据,方法代码
堆:堆是JVM上最大的内存区域,我们申请的几乎所有对象都在堆中存储
五十三:垃圾回收算法
CMS
以获取最短回收停顿时间为目标的收集器,基于标记-清除算法,运行过程为
1.初始标记
标记一下GC Roots能直接关联到的对象,速度很快
2.并发标记
GC Roots Tracing的过程
3.重写标记
修复并发标记期间用户程序继续操作而产生的垃圾
4.并发清除
清除到标记的垃圾由于再次进行并发操作又会产生一部分垃圾
优点:并发收集,低停顿
缺点:CPU资源敏感,无法处理浮动垃圾.有空间碎片
G1:
重新定义了堆空间,打破了原有的分代模型,将堆划分为一个个区域,进行收集时不必全堆范围进行,带来了停顿时间可预测的收集模型,用户可以指定收集操作才多长时间内完成
运行过程:
初始标记:仅仅只是标记一下GC Roots能直接关联到的对象
并发标记:是从GCRoots开始堆中对象进行可达性分析,找出存活的对象
最终标记:修正并发标记期间因用户程序继续操作而产出的垃圾
筛选回收:首先对各个Region的回收价值和成本进行排序,根据用户所期望的GC停顿时间来指定回收计划
特点:
并行与并发:G1能充分利用多CPU,多核环境下的硬件优势,使用多个CPU缩短STW停顿的时间,但可通过并发的方式让java程序继续运行
分代收集
空间整合:G1整体看基于标记-整理算法算法,从局部看基于"复制"算法实现,利于程序长时间运行
可预测的停顿:建立可预测的停顿模型
模型划分:将堆内存模型划分为多个大小相等的Region,使得新生代和老年代不再物理隔离开来
五十四:单点登陆
方案1.用户登陆成功以后,将用户登陆状态存储到redis数据库
方案2:用户登陆成功以后,将用户信息存储到token(令牌),然后写到客户端进行存储
在这套方案中,用户登录成功后,会基于JWT技术生成一个token,用户信息可以存储到这个token中.后续用户在访问资源时,对token内容解析,检查登录状态以及权限信息,无须再访问数据库
JWT:是一个JSON信息传输的开放标准,它可以使用密钥对信息进行数字签名,以确保信息是可验证和可信任的
服务基于业务进行划分,系统(system)服务只提供基础数据(例如用户信息,日志信息等),认证服务(auth)负责完成用户身份的校验,密码的比对,资源服务(resource)代表一些业务服务
五十五:用户登陆流程
用户输入用户名和密码 admin123/admin123456 点击登录按钮
通过vue中的 axios 发起post请求 /user/login,实现用户登录
在UserController中接收用户的请求和参数(json).
先将密码进行加密处理(SHA1,MD5,MD5HASH),根据参数查询数据库.
4.1 查询成功有数据 输入正确 有且只有一个数据
4.2 查询失败没有数据 输入有误.
如果登录成功,则返回token的秘钥(安全性), 利用SysResult对象返回
五十六:三级分类
遍历数据,如果该数据的父级不存在, 准备list集合,将自己作为第一个元素.
遍历数据,如果该数据的父级存在, 获取list集合,将自己追加到其中
1. 获取一级分类列表信息 *
2. 遍历一级菜单,获取二级数据,将二级数据封装到一级中 *
3. 遍历二级菜单,根据二级菜单查询三级数据
4. 将三级数据封装到一级中
五十七:删除三级标签
1. 判断是否为3级标签 直接删除 *
2. 判断是否为2级标签 先删除三级再删除二级 *
3. 判断是否为1级标签 先查询二级,再删除三级和二级再删除一级
五十八:图片上传
- * 1.校验图片类型
- * 2.校验是否为恶意程序
- * 3.将文件分目录存储
- * 4.为了保证图片唯一性,自定义文件名称*/
- @Override
- public ImageVO upload(MultipartFile file) {
- //xxx.jpg/png/gif 防止大小写问题,将所有字母转化为小写
- String fileName=file.getOriginalFilename().toLowerCase();
- //1.利用正则判断是否为图片
- if (!fileName.matches("^.+\\.(jpg|png|gif)$")){
- //如果校验不通过,则终止程序
- return null;
- }
- System.out.println("图片干起咯!!!");
- //2.防止恶意程序 判断图片是否有宽度和高度
- try {
- BufferedImage bufferedImage = ImageIO.read(file.getInputStream());
- int width = bufferedImage.getWidth();
- int height = bufferedImage.getHeight();
- if (width==0||height==0){
- return null;
- }
- System.out.println("用户上传的确实是正儿八经的图片!!");
- //3.目录如何划分 yyyy/MM/dd
- String dataDir=
- new SimpleDateFormat("/yyyy/MM/dd/")
- .format(new Date());
- String dirPath=localDir + dataDir;
- File dirFile=new File(dirPath);
- if (!dirFile.exists()){
- //如果目录不存在 创建目录
- dirFile.mkdirs();
- }
- //4.UUID
- String uuid= UUID.randomUUID()
- .toString().replace("-", "");
- //截取文件类型
- int index =fileName.lastIndexOf(".");
- String fileType=fileName.substring(index);
- //生成新文件名称
- String newFile=uuid+fileType;
- //5.实现文件上传 全路径再上传
- String path=dirPath+newFile;
-
- file.transferTo(new File(path));
- System.out.println("终于成功上传上图片了QAQ");
- //6.返回ImageVO数据
- //6.1虚拟路径只写动态变化的数据
- String virtualPath=dataDir +newFile;
- //6.2真实图片名称
- String fileNameVO=newFile;
- //6.3网络地址
- String url=urlPath+virtualPath;
- System.out.println(url);
- return new ImageVO(virtualPath,url,fileNameVO);
- } catch (IOException e) {
- e.printStackTrace();
- return null;
- }
- }
五十九:分页功能
User
- @Override
- public PageResult getUserListByPage(PageResult pageResult) {
- //1.总数
- long total=userMapper.findTotal();
- //2.分页结果
- int size=pageResult.getPageSize();
- int start=(pageResult.getPageNum()-1)*size;
- String query=pageResult.getQuery();
- //查询分页数据
- List<User> userList=
- userMapper.findUserListByPage(size,start,query);
- //将返回值结果进行封装
- return pageResult.setTotal(total).setRows(userList);
- }
Item
- @Override
- public PageResult getItemList(PageResult pageResult) {
- /*
- * 语法:selectPage语法说明
- * 1.page:Mp内部指定的分页对象
- * 2.queryWrapper 条件构造器*/
- //判断用户的数据是否有值
- boolean flag= StringUtils.hasLength(pageResult.getQuery());
- QueryWrapper<Item> queryWrapper=new QueryWrapper();
- queryWrapper.like(flag, "title",pageResult.getQuery());
- //编辑MP的分页对象 传递(页数/条数) 得到(页数/条数/总数/记录)
- IPage<Item> page=new Page<>(pageResult.getPageNum(),pageResult.getPageSize());
- page= itemMapper.selectPage(page, queryWrapper);
- //获取总数
- long total=page.getTotal();
- //获取记录数
- List<Item> rows=page.getRecords();
- //封装数据
- return pageResult.setTotal(total).setRows(rows);
- }
六十:图片回显
1.启动nginx start nginx
2.重启nginx nginx -s reload
3.关闭nginx nginx -s stop
先进行nginx conf文件的配置,再去hosts文件配置映射关系
在前端里修改属性配置,访问后端服务器域名
前端js不能直接访问图片路径,但是可以通过http协议来访问,而图片路径这些信息是不能给用户看的,所以通过配置nginx反向代理技术来隐藏信息
六十一:前端AJAX的实现
- async findItemCatList() {
- const {
- data: result } = await this.$http.get("/itemCat/findItemCatList/3")
- if (result.status !== 200) return this.$message.error("查询商品分类信息失败")
- this.itemCatList = result.data
- }
六十二:Mybatis和Hibernate的对比
开发速度的对比:
简单的增删改查,hibernate效率更,因为基本的sql语句已经被封装好了,根本不需要我们去写sql语句,这就节省了大量的时间,但是对于一个大型项目复杂语句较多,这样再去选择hibernate就不是一个太好的选择,选择mybatis就会加快许多,而且语句的管理也比较方便。
开发工作量的对比:
Hibernate和MyBatis都有相应的代码生成工具。可以生成简单基本的DAO层方法。针对高级查询,Mybatis需要手动编写SQL语句。而Hibernate有良好的映射机制,开发者不需要关心SQL的生成与结果映射,可以更专注于业务流程
对象管理的对比:
Hibernate是完整的对象/关系映射解决方案,它提供了对象状态管理(state management)的功能
使开发者不再需要理会底层数据库系统的细节。使用Hibernate的开发者应该总是关注对象的状态(state),不必考虑SQL语句的执行。而MyBatis在这一块没有文档说明,用户需要对对象自己进行详细的管理。
缓存机制对比
相同点:都可以实现自己的缓存或使用其他第三方缓存方案,创建适配器来完全覆盖缓存行为。
不同点: Hibernate的二级缓存配置在SessionFactory生成的配置文件中进行详细配置,然后再在具体的表-对象映射中配置是哪种缓存。
六十三:Linux常用命令
1. man 对你熟悉或不熟悉的命令提供帮助解释
2. ls 查看目录或者文件的属性,列举出任一目录下面的文件
3. cp 拷贝文件
4. rm 删除文件和目录
5. mv 移走目录或者改文件名
6. cd 改变当前目录 pwd 查看当前所在目录完整路径
7. cat,more命令
将某个文件的内容显示出来。两个命令所不同的是:cat把文件内容一直打印出来,而 more则分屏显示
8.chmod 命令 权限修改 用法:chmod 一位8进制数 filename。
9. clear,date命令
clear:清屏,相当与DOS下的cls;date:显示当前时间
10. mount 加载一个硬件设备
11. su 在不退出登陆的情况下,切换到另外一个人的身份
12.whoami,whereis,which,id
//whoami:确认自己身份
//whereis:查询命令所在目录以及帮助文档所在目录
//which:查询该命令所在目录(类似whereis)
13. grep,find
grep:文本内容搜索;find:文件或者目录名以及权限属主等匹配搜索
14. kill 可以杀死某个正在进行或者已经是dest状态的进程
15. passwd 可以设置口令
16. history 用户用过的命令
17. !! 执行最近一次的命令
18. mkdir命令 创建一个目录
19. tar 解压命令
20. finger 可以让使用者查询一些其他使用者的资料
21.ps用于将某个时间点的进程运行情况选取下来并输出
22.vim用于文本编辑,文件存在即打开,不存在即创建文件再打开
23.gcc用于把c语言文件转换成可执行文件
24.time用于测算一个命令的执行时间
1.man 对你熟悉或不熟悉的命令提供帮助解释
2.ls/ll 查看目录或者文件的属性,列举出任一目录下面的文件
3.cp 拷贝文件
4.rm 删除文件和目录
5.mv 移走目录或者改文件名
6.cd 改变当前目录 pwd 查看当前所在目录完整路径
7.cat,more命令
将某个文件的内容显示出来。两个命令所不同的是:cat把文件内容一直打印出来,而 more则分屏显示|
8.chmod 命令 权限修改 用法:chmod 一位8进制数 filename。
9. clear,date命令
clear:清屏,相当与DOS下的cls;date:显示当前时间
10. mount 加载一个硬件设备|
11. su 在不退出登陆的情况下,切换到另外一个人的身份
12.whoami,whereis,which,id
//whoami:确认自己身份
//whereis:查询命令所在目录以及帮助文档所在目录
//which:查询该命令所在目录(类似whereis)
13. grep,find
grep:文本内容搜索;find:文件或者目录名以及权限属主等匹配搜索
14. kill 可以杀死某个正在进行或者已经是dest状态的进程
kill -9 进程号
15. passwd 可以设置口令
16. history 用户用过的命令
17. !! 执行最近一次的命令
18. mkdir命令 创建一个目录
19. tar 解压命令
tar -czvf xxx.tar.gz xx/xx/xx.xx 压缩文件
tar -xzvf xxx.tar.gz 解压文件
20. finger 可以让使用者查询一些其他使用者的资料
21.ps用于将某个时间点的进程运行情况选取下来并输出
ps -ef|grep 进程号
22.vim用于文本编辑,文件存在即打开,不存在即创建文件再打开
23.gcc用于把c语言文件转换成可执行文件
24.time用于测算一个命令的执行时间
25.netstat 查询端口对应的进程号
netstat -anp|grep 7013
26.du -sh 文件名 查看文件大小
27.jps -v 查看当前java运行的端口
28. ./bin/startup.sh 重启项目
29. tail -f logs/catalina.out 查看启动日志
30.chown whaty.whaty pages.tar.gz 赋予pages文件whaty用户权限
31.su - whaty使用用户权限
六十四:Docker常用命令
1.docker version 查看容器版本
2.docker images 查看全部镜像 -a 包含中间的映射层 -q只查看id
3.docker search 镜像名 搜索镜像
4.docker pull 镜像名 下载镜像最新的版本
5.docker rmi 镜像名 删除镜像 -f强制删除
6.docker start 镜像名 启动镜像 stop 停止镜像 restart 重启镜像
7.docker run 启动容器 -i交互方式运行 -t分配终端 --name定义容器名称
8.docker top 容器 查看容器运行的进程
9.docker logs 容器 查看容器日志
10.docker exec 容器 bush 运行容器
11.docker ps 查看正在运行的容器
12.docker rm 容器 删除容器 -f强制删除
六十五:SQL优化
1.查询SQL尽量不要使用select *
2.结构设计时用Varchar来代替Char
3.查询尽量避免返回大量的数据
4.优化Like
5.索引不宜太多
6.使用默认值代替null
六十六:各大排序
冒泡排序:
基本思想:两个数比较大小,较大的数下沉,较小的数冒起来。
过程:
选择排序:
基本思想:
在长度为N的无序数组中,第一次遍历n-1个数,找到最小的数值与第一个元素交换;
第二次遍历n-2个数,找到最小的数值与第二个元素交换;
。。。
第n-1次遍历,找到最小的数值与第n-1个元素交换,排序完成。
插入排序:
基本思想:
在要排序的一组数中,假定前n-1个数已经排好序,现在将第n个数插到前面的有序数列中,使得这n个数也是排好顺序的。如此反复循环,直到全部排好顺序。
希尔排序:
基本思想:
在要排序的一组数中,根据某一增量分为若干子序列,并对子序列分别进行插入排序。
然后逐渐将增量减小,并重复上述过程。直至增量为1,此时数据序列基本有序,最后进行插入排序。
快速排序:
基本思想:(分治)
归并排序:
基本思想:
归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法的一个非常典型的应用。
首先考虑下如何将2个有序数列合并。这个非常简单,只要从比较2个数列的第一个数,谁小就先取谁,取了后就在对应数列中删除这个数。然后再进行比较,如果有数列为空,那直接将另一个数列的数据依次取出即可。
基数排序:
基本思想:
BinSort想法非常简单,首先创建数组A[MaxValue];然后将每个数放到相应的位置上(例如17放在下标17的数组位置);最后遍历数组,即为排序后的结果。
方向:无锁->偏向锁->轻量级锁->重量级锁
线程之间没有锁的竞争,就是无锁状态,如果总是由同一个线程多次获得则升级为偏向锁(jdk6时引入的,偏向于第一个获取它的线程,执行流程:当对象头的线程id和当前线程相同执行代码,不相同就使用CAS的方式替换掉对象头的线程id),如果有其他线程来参与锁的竞争,但冲突的时间很短,此时就升级为轻量级锁,在冲突过程中,会用自旋的方式循环获取锁,如果有大量的线程参与锁的竞争,线程一定时间内没有获取到锁的话则升级为重量级锁.
进程是操作系统资源分配的基本单位,而线程是处理器任务调度和执行的基本单位.一个进程内有多个线程,线程是进程的一部分.同一进程内的线程共享本进程的资源和地址空间,而线程之间的资源和地址空间相互独立.
1.线程是程序执行的最小单元,一个进程可以拥有多个线程
2.各个线程之间共享程序的内存空间(代码段、数据段和堆空间)和系统分配的资源(CPU,I/O,打开的文件),但是各个线程拥有自己的栈空间
3.多线程优点:减少程序响应时间;提高CPU利用率;创建和切换开销小;数据共享效率高;简化程序结构
管道、命名管道、信号、消息队列、共享内存、内存映射、信号量、Socket
常用的设计模式有单例模式、工厂方法模式、代理模式、适配器模式、装饰器模式、模板方法模式,享元模式等等。像sping中的定义的bean默认为单例模式,spring中的BeanFactory用来创建对象的实例,他是工厂模式的体现。AOP面向切面编程时代理模式的体现,它的底层就是基于动态代理实现的。适配器模式在springMVC中有体现,它的处理器适配器会根据处理器规则适配相应的处理器执行,模板方法模式用来解决代码重复的问题,而享元主要体现在线程池上等
物理内存是计算机中真实拥有的内存,内存是有限的,容易产生内存不足问题。
虚拟内存是一种抽象的逻辑概念,拥有连续的内存地址。在编译程序时,要将虚拟内存地址映射成物理内存地址
linux操作系统采用段页式内存管理方式:页式存储管理可以有效的提高内存利用率,段式内存管理能反映程序的逻辑结构并有利于段的共享。将这两种方法结合起来就形成了段页式储存管理方式。段页式储存管理方式就是先建好用户程序分成若干个段,再把每个段分成若干页,并为每个段赋予一个段名。
IO多路复用是指单个线程或进程能够处理多个IO请求。
select调用主要统计有多少个文件描述符需要进行IO操作。缺点:内存开销大,支持的的文件描述符的个数有限。
poll和select调用差别不大,主要是底层数据结构变成了链表,支持的文件描述符的个数无上限。
epoll调用是更加高效的方式,底层数据结构使用了红黑树和链表,避免了大量的内存分配和轮询。
1. 线程是操作系统的资源,线程的创建、切换、停止等都非常消耗资源,而创建协程不需要调用操作系统的功能,编程语言自身就能完成,所以协程也被称为用户态线程,协程比线程轻量很多;
2. 线程在多核环境下是能做到真正意义上的并行,而协程是为并发而产生的;
3. 一个具有多个线程的程序可以同时运行几个线程,而协同程序却需要彼此协作的运行;
4. 线程进程都是同步机制,而协程则是异步;
5. 线程是抢占式,而协程是非抢占式的,所以需要用户自己释放使用权来切换到其他协程,因此同一时间其实只有一个协程拥有运行权,相当于单线程的能力;
6. 操作系统对于线程开辟数量限制在千的级别,而协程可以达到上万的级别
运用先更新数据库、再删除缓存的方案。如果出现失败的情况,则可以采用重试机制解决问题。
1、Java通过加锁实现线程同步,锁有两类:synchronized和Lock。
2、synchronized加在三个不同的位置,对应三种不同的使用方式,这三种方式的区别是锁对象不同:
(1.)加在普通方法上,则锁是当前的实例(this)。 (2.)加在静态方法上,锁是当前类的Class对象。 (3.)加在代码块上,则需要在关键字后面的小括号里,显式指定一个对象作为锁对象。
3、Lock支持的功能包括:支持响应中断、支持超时机制、支持以非阻塞的方式获取锁、支持多个条件变量(阻塞队列)。
synchronized可以修饰静态方法、普通方法、代码块。 能够保证同一个时刻只有一个线程执行该段代码,保证线程安全。在执行完或者出现异常时自动释放锁。synchronized的底层是采用Java对象头来存储锁信息的,并且还支持锁升级。
Lambda 表达式 − Lambda 允许把函数作为一个方法的参数(函数作为参数传递到方法中)。
方法引用 − 方法引用提供了非常有用的语法,可以直接引用已有Java类或对象(实例)的方法或构造器。与lambda联合使用,方法引用可以使语言的构造更紧凑简洁,减少冗余代码。
默认方法 − 默认方法就是一个在接口里面有了一个实现的方法。
新工具 − 新的编译工具,如:Nashorn引擎 jjs、 类依赖分析器jdeps。
Stream API −新添加的Stream API(java.util.stream) 把真正的函数式编程风格引入到Java中。
Date Time API − 加强对日期与时间的处理。
Optional 类 − Optional 类已经成为 Java 8 类库的一部分,用来解决空指针异常。
Nashorn, JavaScript 引擎 − Java 8提供了一个新的Nashorn javascript引擎,它允许我们在JVM上运行特定的javascript应用。
1,强引用,以new关键字创建的引用都是强引用,被强引用引用的对象永远都不会被回收。
2,软引用:以SoftRererenc引用对象,被弱引用引用的对象只有在内存空间不足时会被垃圾回收。
3,弱引用,以WeakReference引用对象,被弱引用引用的对象一定会被回收,它只能存活到下一次垃圾回收。
4,虚引用:以PhantomReference引用对象,一个对象被引用引用后不会有任何影响,也无法通过该引用来获取该对象,只是其再被垃圾回收时会收到一个系统通知。
惰性删除:客户端访问一个key的时候,Redis会先检查它的过期时间,如果发现过期就立刻删除这个key。
定期删除:Redis会将设置了过期时间的key放到一个独立的字典中,并对该字典进行每秒10次的过期扫描, 过期扫描不会遍历字典中所有的key,而是采用了一种简单的贪心策略。该策略的删除逻辑如下: 1. 从过期字典中随机选择20个key; 2. 删除这20个key中已过期的key; 3. 如果已过期key的比例超过25%,则重复步骤1
项目创建完成后默认生成一个Application的入口类,通过调用run方法进行SpringApplication的实例化操作,然后再调用另外一个run方法来->获取监听器参数配置->打印Banner信息->创建并初始化容器->监听器发送通知 以此完成项目启动.
Bean的生命周期主要包括:Bean定义,Bean初始化,Bean生存期,Bean销毁。 具体流程如下:1,spring启动,查找并加载所需的Bean,然后初始化。2,进行Bean的属性依赖注入。3,如果Bean实现了BeanNameAware接口(@Resource,@Qualifier),spring会将Bean的Id传入SetBeanName方法去执行。4,如果Bean实现了BeanFactoryAware接口,spring会调用Bean的setBeanFactory方法将BeanFactory的ioc容器传入。5,如果Bean实现的时ApplicationContextAware接口的话,Spring会调用Bean的setApplicationContext将Bean应用的上下文传入进来。6,还一些其他的设定例如使用@PostContruct来定义Bean在初始化时执行的方法,或者使用@PreDestory来定义Ioc容器被销毁时执行的方法等
三次握手:
1、第一次握手:客户端给服务端发一个 SYN 报文,并指明客户端的初始化序列号 ISN(c)。此时客户端处于 SYN_Send 状态。
2、第二次握手:服务器收到客户端的 SYN 报文之后,会以自己的 SYN 报文作为应答,并且也是指定了自己的初始化序列号 ISN(s),同时会把客户端的 ISN + 1 作为 ACK 的值,表示自己已经收到了客户端的 SYN,此时服务器处于 SYN_REVD 的状态。
3、第三次握手:客户端收到 SYN 报文之后,会发送一个 ACK 报文,当然,也是一样把服务器的 ISN + 1 作为 ACK 的值,表示已经收到了服务端的 SYN 报文,此时客户端处于 establised 状态。
4、服务器收到 ACK 报文之后,也处于 establised 状态,此时,双方以建立起了链接。
四次挥手:
1、第一次挥手:客户端发送一个 FIN 报文,报文中会指定一个序列号。此时客户端处于FIN_WAIT1状态。
2、第二次握手:服务端收到 FIN 之后,会发送 ACK 报文,且把客户端的序列号值 + 1 作为 ACK 报文的序列号值,表明已经收到客户端的报文了,此时服务端处于 CLOSE_WAIT状态。
3、第三次挥手:如果服务端也想断开连接了,和客户端的第一次挥手一样,发给 FIN 报文,且指定一个序列号。此时服务端处于 LAST_ACK 的状态。
4、第四次挥手:客户端收到 FIN 之后,一样发送一个 ACK 报文作为应答,且把服务端的序列号值 + 1 作为自己 ACK 报文的序列号值,此时客户端处于 TIME_WAIT 状态。需要过一阵子以确保服务端收到自己的 ACK 报文之后才会进入 CLOSED 状态
5、服务端收到 ACK 报文之后,就处于关闭连接了,处于 CLOSED 状态。
用法:标注在成员变量上,或者set方法上。@Autowired 与 @Resource 都是用于bean自动装配的;
区别:@Autowired装配默认是通过类型去查找,也可以通过@Qualifier指定名称查找。而@Resource 默认按照名称进行查找,当然也可指定类型、指定名称或者同时指定。指定类型的时候如果找不到或者找到多个都会抛出异常。同时指定类型和名称的时候,会去找唯一匹配的bean,如果找到多个抛出异常。
用法:都是标注在类名上,用于注册一个bean到Spring上下文中。
区别:@Service 用于服务层;@Controller用于控制层;@Repository用于DAO层;不确定的用@Component
用法:@RequestMapping标注在控制层类上面映射一个请求路径;@RequestParam 映射一个请求参数;
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。