阿里钉钉、天猫、同程、百度春招暑期Java实习重点面经综合(已拿offer)

每面完一个就按照知识点分类插入了,所以也忘记了哪一个题是哪家公司的面经,不过这是我近半月被问到过的几乎所有题目,已拿offer,面经就发出来希望能帮到大家吧...

七大排序的时间复杂度

排序类别时间复杂度空间复杂度稳定
插入排序O(n2)1
希尔排序O(n2)1
冒泡排序O(n2)1
选择排序O(n2)1
快速排序O(Nlogn)O(logn)×
堆排序O(Nlogn)1×
归并排序O(Nlogn)O(n)

跳表

  • 跳表其实就是一种可以进行二分查找的有序链表

  • 跳表在原有的有序链表上面增加了多级索引,通过索引来实现快速查找。首先在最高级索引上查找最后一个小于当前查找元素的位置,然后再跳到次高级索引继续查找,直到跳到最底层为止,这时候以及十分接近要查找的元素的位置了(如果查找元素存在的话)。由于根据索引可以一次跳过多个元素,所以跳查找的查找速度也就变快了

AVL树

  • 一般用平衡因子判断是否平衡并通过旋转来实现平衡,左右子树树高不超过1,和红黑树相比,AVL树是高度平衡的二叉树,平衡条件必须满足(所有节点的左右子树高度差不超过1)。不管我们是执行插入还是删除操作,只要不满足上面的条件,就要通过旋转来保持平衡,而的由于旋转比较耗时,由此我们可以知道AVL树适合用于插入与删除次数比较少,但查找多的情况,还是使用AVL树优于红黑树

红黑树

  • 红黑树是一种特定类型的二叉树,它是在计算机科学中用来组织数据比如数字的块的一种结构。若一棵二叉查找树是红黑树,则它的任一子树必为红黑树.
  • 红黑树是一种平衡二叉查找树的变体,它的左右子树高差有可能大于 1,所以红黑树不是严格意义上的平衡二叉树(AVL),但 对之进行平衡的代价较低, 其平均统计性能要强于 AVL 。
  • 由于每一棵红黑树都是一颗二叉排序树,因此,在对红黑树进行查找时,可以采用运用于普通二叉排序树上的查找算法,在查找过程中不需要颜色信息。
  • 插入删除次数较多的时候用红黑树很快
  • O(logN)

B+树和B树的区别

  • B树每个节点都存储key和data,所有节点组成这棵树,并且叶子节点组成为null
  • B+树只有叶子结点存储data,叶子结点包含了这棵树的所有键值,叶子结点不存储指针

为什么数据库用B+树而不是B树或红黑树

  • 红黑树必须存在内存中,数据库表太大了,而且红黑树查询要O(logN)层,每次查询要logN次IO,速度太慢
  • B树每个节点都存储数据,这样就会导致整个树存储的数据量变少,而看B+树,只有叶子结点存储数据,非叶子节点只起到导向作用,只存储一个导向的整数即可,所以树高度就变低,查询速度很快。而且B+树的叶子结点有链表相连,适合范围查询,而B树不是。

String不可变的原理是什么,为什么要设计成不可变的

  • String底层是char数组,char数组是final修饰的,所以不可变。
  1. 如果String可变,字符串常量池会引起混乱。
  2. String缓存了自己的hash,如果可变,hashmap、hashset会出现问题
  3. String经常用作参数,如果可变不安全

Object中有哪些方法:

  • getClass():返回此Object的运行类
  • hashCode():返回此对象的哈希值
  • toString():返回此对象的字符串显示
  • wait():等待线程
  • notify():唤醒运行在此对象上的单个线程
  • notify():唤醒所有线程
  • finalize():当垃圾回收器确定没有这个对象更多引用时候,调用这个方法清除对象

int和Integer的区别

  • int是基本数据类型,Integer是包装类
  • Integer必须实例化才能使用,int不需要
  • Integer的初始值是null,int是0
  • Integer实际是对象引用,当new一个Integer的时候实际上是生成一个指针指向该对象。而int是直接存储值。

abstractClass和Interface的区别

  • 抽象类不可以实例化、接口可以实例化
  • 抽象类只能被单继承,一个类可以实现多个接口
  • 抽象类方法可以私有,非abstract方法必须实现,接口不可以有私有方法
  • 抽象类可以有私有变量,接口不可以有私有变量,默认public static final
  • 抽象类是继承extends,接口是实现implement

synchronized和lock的区别

  • synchronize是关键字而lock是接口
  • synchronize在程序发生异常时会自动释放锁,所以不会发生异常死锁,而lock不会释放,需要在finally中释放锁
  • lock是可中断锁,synchronize是非中断锁,必须线程执行完再中断锁
  • lock可以使用读锁提高多线程读效率

synchronize实现原理

  • synchronized的功能是基于monitorenter和monitorexit指令实现的。monitorenter指令是在编译后插入到同步代码块的开始位置,而monitorexit是插入到方法结束处和异常处,JVM要保证每个monitorenter必须有对应的monitorexit与之配对。任何对象都有一个monitor与之关联,当且一个monitor被持有后,它将处于锁定状态。线程执行到monitorenter指令时,将会尝试获取对象所对应的monitor的所有权,即尝试获得对象的锁。
  • synchronize修饰的方法有一个ACC_SYNCHRONIZED标识,该标识指明了该方法是一个同步方法,JVM通过该ACC_SYNCHRONIZED访问标志来辨别一个方法是否声明为同步方法,从而执行相应的同步调用。这便是synchronized锁在同步代码块和同步方法上实现的基本原理。

volatile线程安全吗?

  • volatile能保证数据可见性,但不能保证数据操作的原子性,所以是线程不安全的

synchronized 和 ReentrantLock的区别

  • synchronize是一个关键字,而ReentrantLock是一个API层面的互斥锁
  • ReentrantLock提供了一些高级功能:
    1. 等待可中断:持有锁的线程长期不释放时,等待的线程可以选择放弃等待
    2. 公平锁:多个线程同时等待锁时,必须按照申请时间获得锁
    3. 锁绑定多个条件:ReentrantLock可以按条件分组唤醒需要唤醒的线程,而不是像synchronize那样随机唤醒一个线程或全部线程。

什么是JUC

  • Java并发编程的一个工具类

进程与线程的区别

  • 进程是程序对于数据的一次活动,资源分配的最小对象
  • 一个进程可以有多个线程,线程不能拥有资源,线程是处理器任务调度和执行的基本单位。

线程的创建方式

  • 继承Tread类
  • 实现Runnable接口
  • 实现Callable接口

进程的状态

  • 分为五种状态:新建态、就绪态、终止态、运行态、阻塞态

进程的通信方式

  1. 管道,具有特定的读端和写端,只能用于具有亲缘关系线程之间的通信
  2. FIFO:命名管道,可以在无关进程之间通信
  3. 消息队列,消息的链接表,消息队列独立于发送与接收进程,进程终止后消息队列及内容不会删除
  4. 信号量:用于实现进程的互斥和同步
  5. 共享内存:两个或多个进程共享一个给定的存储区

线程的通信方式

  1. volilate关键字:多个线程同时监听一个变量,当这个变量发生变化时,线程就可以感知到并执行相应业务
  2. Object的wait()、notify()、notifyAll()方法
  3. LockSupport实现线程的阻塞和唤醒
  4. 使用JUC工具类CountDownLatch
  5. ReentrantLock结合Condition

乐观锁和悲观锁的区别

  • 乐观锁就是每次拿数据都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新数据
  • 悲观锁就是每次拿数据都认为别人会修改,所以拿数据也要加锁,别人要拿数据就会block直到他拿到锁

StringBuilder和StringBuffer的区别

  • StringBuilder和StringBuffer都是字符串缓冲区,区别就是StringBuffer的方法使用了synchronize,是线程安全的,而StringBuilder是线程不安全的,相对的,StirngBuilder效率高于StringBuffer

插入数据ArrayList和LinkedList谁效率高

  • 因为ArrayList底层是一个数组,但ArrayList是一个可扩容的数组,如果插入多条数据的话,ArrayList会扩容,所以插入效率要慢,而且插入或删除数据ArrayList需要重排数组中的数据,也导致插入效率慢。但如果是插入一条数据的话,如果在末尾插入那么ArrayList、LinkedList速度相似,如果在中间插入那么LinkedList效率高。LinkedList底层是一个双链表,在添加删除时效率更好,所以LinkedList插入效率更高,而ArrayList查找效率更高。

HashMap原理

  • HashMap与HashTable一样都是Map结构,HashMap实现的是AbstraceMap类,而且是线程不安全的,在多线程开发中可以使用ConcurrentHashMap。
  • HashMap支持key-value为null,但只能有一个key为null,因为要保证key的唯一性,但可以有多个value为null
  • HashMap的底层是数组+链表+红黑树,HashMap根据键的hashCode值来存储元素,所以在查找数据的时候速度很快,但HashMap是无序的。
  • 在HashMap存储元素时,先将hashCode相同的值分组,如果有多个hashCode相同的值,那么如果超过8个就用红黑树连接一起,如果不超过就用链表连接到一起。这也是处理哈希冲突的一种方法:拉链法。

HashSet

  • HashSet底层是HashMap,但是效率要比HashMap低,因为HashMap有唯一 的key对应value。HashSet是Set,所以具有不重复性,但也正因为是Set,导致get数据比较麻烦。
  • HashSet判断值是否重复有两个方面,一个是对象的哈希值,如果哈希值一样那么就比较equals,如果equals也一样,那么HashSet就判断是同一对象,如果equals不一样,那么就在同一哈希值下顺延形成一个哈希桶。

TreeSet

  • TreeSet是使用二叉树的原理对新add()的对象按照升序或降序排序,然后将对象插入二叉树的指定位置
  • Integer和String对象都是可以进行默认TreeSet排序的,而自定义的对象不行,需要自己继承Comparable重写comparaTo才能实现

解决哈希碰撞的几种方式:

  • 拉链法:哈希表节点都有个next指针,多个哈希节点可以连成一个链表,这也是HashMap解决哈希碰撞的方法
  • 开放地址法:一旦发生冲突就去找下一个空散列地址,只要散列表足够大, 肯定能找到一个
  • 再hash:当一个hash值重复时,再使用第2、3…个hash函数计算哈希值,直到不相同为止

ConcurrentHashMap实现原理

  • ConcurrentHashMap与HashMap类似,1.8之前:ConcurrentHashMap由多个Segment(分段锁)组成,ConcurrentHashMap就是一个Segment数组,所以每次需要加锁的操作锁住的都是Segment,这样就实现了每个Segment都是线程安全的,就保证了全局线程安全,Segment默认16个,也就是说支持16个线程并发写。1.8之后:ConcurrentHashMap抛弃了分段锁的概念,改为用synchronize和cas来保证并发安全,synchronize只锁住当前链表和红黑二叉树的首节点,只要哈希值不冲突,就不会产生并发,效率很高。

List<>、List、List<?>泛型的区别

  • List<>没有使用泛型,向其中添加不同类型的元素,所有功能都能正常使用,但可能会出现强制类型转换异常
  • List<Object>:可以存储任意类型的元素,但不能被其他泛型赋值,因为泛型间只有同类型才能赋值
  • List<?>:可以接受任何对应List<E>的参数化类型,但不能被任何非null的元素赋值

类型擦除:

  • Java中的泛型基本都是在编译器这个层面实现的,在生成的Java字节码文件中是不包含泛型中的类型信息的。使用泛型的时候加上的类型参数,要在被编译器编译的时候去掉,这就是类型擦除。

多路复用IO

  • 在多路复用IO模型中,会有一个线程去不断轮训多个socket状态,只有当socket真正有读写事件时,才真正调用IO读写操作,因为在多路复用IO模型中,只需要一个线程就可以管理多个socket,系统不需要再建立新的线程或进程,只有在真正有socket读写的时候才使用IO资源,减少了资源占用。因为多路复用IO是通过轮询的方式来检测是否有事件到达,如果前面到达的事件体很大,就会造成后面的事件得不到处理,影响新的事件轮询。

NIO

  • NIO有三大核心部分:Channel(通道)、Buffer(缓冲区)、Selector(选择区)。传统IO基于字节流与字符流操作,而NIO基于Channel和Buffer操作,数据总是从通道读到缓冲区中,或者从缓冲区写入通道中。Selector用与监听多个通道事件(如:连接打开、数据到达)。因此单个线程可以监听多个数据通道。
  • NIO与IO的最大区别在于,IO是面向流的而NIO是面向缓冲区的

NIO的非阻塞模式

  • NIO的非阻塞模式,使一个线程从某通道发送请求读取数据,它仅能得到当前可用的数据,如果当前无可用数据,那么就什么都不会获取,而不是保持线程阻塞,直到数据变为可用之前, 该线程都可做其他工作。非阻塞写也是如此。一个线程请求写入一些数据到某通道,但不需要等待它完全写入,这个线程同时可以去做别的事情。

代理模式

  • 角色分析:
    抽象角色:一般会使用接口或抽象类来解决
    真实角色:被代理的角色
    代理角色:代理真实角色,代理真实角色后,一般会做一些附属工作
    客户角色:访问代理角色的人
  • 用房东、客户、中介来解释这个关系就是,房东的目的是租房,找到中介作为代理,代理把房子租给用户的同时还能实现签合同和看房等方法,这样既满足了房东的要求,也能自己做一些附加要求。
  • 动态代理的代理类是直接生成的

工厂模式有哪几种工厂

1.使用场景:

  1. 类不知道自己要创建哪一个对象
  2. 类用它的子类来指定创建哪个对象
  3. 客户需要清楚创建了哪一个对象

2.三种不同工厂的区别

  • 简单工厂:针对一种产品。缺点是破坏了开放,封闭原则。
  • 工厂模式: 对简单工厂做了相应的改进,改正了简单工厂破坏开放封闭原则的错误。
  • 抽象工厂:针对于多种产品,和简单工厂以及工厂模式并无太大的关联。

TCP和UDP的区别

  • TCP 是面向连接的,UDP 是面向无连接的
  • UDP程序结构较简单
  • TCP 是面向字节流的,UDP 是基于数据报的
  • TCP 保证数据正确性,UDP 可能丢包
  • TCP 保证数据顺序,UDP 不保证

TCP有三次握手四次挥手,比UDP安全

什么是http协议

  • 每次HTTP请求都是独立的,任何两个请求之间没有什么必然的联系。但是在实际应用当中并不是完全这样的,引入了Cookie和Session机制来关联请求。
  • HTTP底层是基于TCP实现的。现在使用的版本当中是默认持久连接的,也就是多次HTTP请求使用一个TCP连接。

HTTP协议状态码

  • 100 :请求继续发送请求
  • 200:成功,操作被成功接收并处理
  • 300:重定向,需要进一步操作以完成请求
  • 400:客户端错误
  • 500:服务端错误

TCP的三次握手和四次挥手

  • 三次握手

    • 客户端发送一个SYN请求连接
    • 服务端收到后返回一个ACK确认码和一个SYN
    • 客户端收到后再次发送一个ACK确认码
  • 四次挥手

    • 客户端发送一个FIN请求断开连接
    • 服务端收到后返回一个ACK确认码
    • 服务端数据传输完成后,发送一个FIN断开连接请求
      -客户端收到后发送一个ACK确认码

TCP滑动窗口机制

  • 在三次握手阶段确定窗口大小,确定完窗口大小后,接收方接收数据,对数据确认然后告诉发送方下次希望接收到的数据大小是多少。如果发送方接收到接收方传来的接收为0的窗口,就会停止发送。

网络七层模型

  • 物理层—数据链路层—网络层—传输层—会话层—表示层—应用层

访问url的过程:

  • DNS解析
  • 负载均衡
  • Web服务器
  • 浏览器渲染

Spring创建bean的流程是什么

  • 获取BeanName
  • 合并Bean定义
  • 实例化
  • 属性填充
  • 初始化
  • 获取最终的bean

SpringBean的Scope(作用域)

  • SpringBean有五种作用域:单例、prototype、session、request、global session
  • 单例:当一个bean的作用域设置为单例时,Spring IOC只会创建该bean的唯一实例
  • prototype:每发起一个请求,就会产生一个新的实例,但Spring不对prototype bean的整个生命周期负责
  • request:request表示每次Http请求都会产生一个新的bean,这个bean仅在HTTP request内有效
  • session:session作用域表示每次HTTP请求都会产生一个新的bean,这个bean仅在HTTP Session内有效
  • global session:类似于session作用域,但只在特定情况下有效(基于portlet的web应用)

Spring的IOC和AOP

  • IOC:控制反转,是一种设计思想,就是 将原本在程序中手动创建对象的控制权,交由Spring框架来管理。IOC 容器就像是一个工厂一样,当我们需要创建一个对象的时候,只需要配置好配置文件/注解即可,完全不用考虑对象是如何被创建出来的。
  • AOP:面向切面编程,能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护性。

AOP是如何实现的

  • AOP是基于动态代理实现的,如果要代理的对象,实现了某个接口,那么Spring AOP就会使用JDK Proxy,去创建代理对象,而对于没有实现接口的对象,就无法使用JDK Proxy来代理了,这时SpringAOP会使用cglib,用cglib来生成一个被代理对象的子类进行代理

cglib是什么

  • cglib是一个字节码增强库,为AOP实现底层支持,重写了Intercept(拦截器)方法

SpringMVC的请求过程、浏览器请求页面过程

  1. 浏览器的请求直接发送到DisptacherServlet
  2. DisptacherServlet调用HandlerMapping解析Handler
  3. 然后由HandlerAdapter来处理Handler
  4. HandlerAdapter根据Handler调用真正的处理器处理逻辑
  5. 处理器处理完后会返回一个ModelAndView,Model是返回的数据对象,View是逻辑视图
  6. ViewResolver会根据逻辑View查找实际View
  7. DispatcherServlet会将Model传递给View(视图渲染)
  8. 然后把View返回给浏览器

IOC(控制反转)和DI(依赖注入)实现

  • 依赖注入可以通过setter方法注入(设值注入)、构造器注入和接口注入三种方式来实现,Spring支持setter注入和构造器注入,通常使用构造器注入来注入必须的依赖关系,对于可选的依赖关系,则setter注入是更好的选择,setter注入需要类提供无参构造器或者无参的静态工厂方法来创建对象。

Cookie和Session的区别

  • Session是用来标记用户的,用Session来识别具体的某个用户。Session是保存在服务端的,有一个唯一标识。在服务端保存Session的方法有很多,内存、数据库、文件都有
  • 每次Http请求的时候,客户端都会发送相应的Cookie信息到服务器,大多数应用都是用Cookie来实现Session跟踪的,第一次创建Session的时候,服务端会在HTTP协议中告诉客户端,在Cookie中记录一个Session ID,以后每次把这个ID发送给服务器,就知道这个用户是谁了。如果客户端浏览器禁用了Cookie,那么就用用到URL重写技术来进行会话跟踪,每次HTTP交互,URL后会被附加上一个sid=xxxx这样的参数,服务端根据这个参数来识别用户
  • Cookie是用来保存用户信息的,比如登陆过一个网站,下次再登录,就可以直接用Cookie中的信息,不需要再输用户名了。

@Controller和@RestController的区别

  • 使用@Controller在对应方法上,视图解析器就可以解析return的html页面,并且跳转到那个页面,如果返回json等内容到页面,还需要加上@ResponseBody。
  • @RestController就是@ResponseBody和@Controller合在一起的作用

HTTP和HTTPS的区别

  • HTTP传输数据都是明文传输,数据都是未加密的。HTTPS传输数据都是密文传输,比HTTP安全
  • HTTP的传输速度比HTTPS高,因为HTTP只需要三次握手建立连接,而HTTPS还需要ssl的握手的9个包,一共需要发送12个包,所以比HTTP慢
  • HTTP的端口默认80,HTTPS默认443
  • HTTPS就是构建在SSL\TLS上的HTTP协议,比HTTP更耗费服务器资源

快重传

  • 当服务端发送几段报文,客户端接收到第一段,返回一个ACK2,当第二段丢失的时候,会重复发送冗余ACK2,当服务端重复接受三次冗余ACK2时,就知道第二段丢失了,于是重发

超时重传

  • 当一个报文段丢失时,会等待一段时间然后重传分组
  • 当等待的时候,可能后面的报文段已经被接收端接受,但由于等待时间没有得到确认,导致发送端认为后一段也丢失,造成不必要重传,浪费资源

GC算法

  • GC:分代收集算法:
  • 引用计数法:每个对象都有一个计数器,对象每使用一次,对应的计数器就+1,当计数器为0的时候就对这个对象进行垃圾回收,但是每个计数器也有消耗,所以比较浪费资源。
  • 复制算法:新生代 :Eden区经轻GC后存活下来的对象进入幸存者区,然后从幸存者from区将所有对象复制到to区,然后将from区清空。然后to、from进行区域互换。复制算法好处就是没有内存碎片,但是浪费大块内存空间,因为to区永远是空的。所以在存活率较低的新生代使用
  • 标记清除、标记压缩算法:先扫描对象,对活着的对象进行标记,然后执行清除算法,清除掉没有标记的对象,这样会产生很多内存碎片,所以需要标记压缩算法来压缩这些内存碎片,所以适合在存活率较高的老年区使用这种算法。

几种垃圾回收器

  • 新生代收集器
    1. Serial
    2. ParNew
    3. parallel
  • 老年代收集器
    1. Serial Old
    2. CMS
    3. Parallel Old
  • 新生代和老年代收集器
    1. G1

Java内存模型-JMM

  • JMM定义了主内存和线程之间的关系。线程之间的共享变量储存在主内存(Main Memorry)中,每个线程都有一个私有的本地内存(Local Memorry),本地内存中存储了该线程以读\写共享变量的副本。本地内存是一个抽象的概念,并不真实存在。
  • 线程的工作内存都是从主内存中拷贝的,所以这也导致在线程工作内存中做的操作对于主内存和其他线程是不可见的,于是就要用volilate和synchronize关键字来保证同步。

双亲委派机制

  • 简单来说双亲委派机制就是,一个类开始执行要从底层(最底层:虚拟机自带的类加载器)向外层(最外层:应用程序类加载器)开始找这个类,一层一层向上找,哪一层最先有同名类就先执行哪一层,这样就可以防止外层恶意类访问到内层类。

MySQL两种引擎的区别

  • Innodb引擎:Innodb引擎提供了对数据库ACID的支持,并且实现了SQL标准的四种隔离级别,还提供了行级锁和外键约束,MySQL运行Innodb时会在内存中建立缓冲池,用于缓冲数据和索引,当需要使用数据库事务的时候,Innodb引擎是首选,但并没有存储表的行数,所以查询数量的时候要扫描全表。
  • MyIASM引擎:MySQL默认的引擎,不提供事务的支持,也不提供行级锁和外键约束,但存储了表的行数,如果仅仅需要大量读表很少需要事务,那么MyIASM也是好选择。

什么是索引:

索引(Index)是帮助MySQL高效获取数据的数据结构,常见的查询算法,顺序查找,二分查找,二叉排序查找,哈希散列法,分块查找,平衡多路搜索树B树,索引是对数据库表中一个或多个列的数据进行排序的结构,建立索引有助于快速获取信息。索引也不是越多越好,创建索引也需要耗费资源,一是增加了数据库的存储空间,二是在插入和删除时要花费较多的时间去维护索引。

  • 索引加快了查找速度
  • 索引会降低插入、删除、修改等维护任务的速度
  • 唯一索引可以确定每一行数据的唯一性
  • 通过使用索引,可以在查询的过程中使用优化隐藏器,提高系统性能
  • 索引需要占物理和数据空间

聚簇索引和非聚簇索引

  • 聚簇索引:将数据与存储索引放在了一块,找到了索引就找到了数据
  • 非聚簇索引:数据存储与索引分开存放,索引的叶子结点指向数据存储的行数,MyIASM通过key_buffer将索引缓存到内存中,当需要访问数据时候,直接在内存中查找索引。但到key_buffer未命中时,速度较慢。

事务

  • ACID:原子性、一致性、隔离性、永久性
  • 隔离级别包括四个级别
    • read_uncommited: 最低隔离级别,允许读取未提交的数据(脏读幻读不可重复读)
    • read_commited:允许读取已提交数据,阻止了脏读(幻读不可重复读)
    • repeatable_read:可重复读,多次读取结果一致阻止了脏读不可重复读(幻读)(默认隔离级别)
    • serializable:最高级别,服从ACID。但会影响性能

脏读幻读

  • 脏读:当A读取B修改但未提交的数据,如果B回滚,那么A读取的数据无效
  • 幻读:两次完全一样的查询,两次查询的结果集不同

数据库的优化方法

  • 选择合适的字段,并将字段设置为not null,这样就无须比较null值
  • 使用关键字查询(left、join、on)代替子查询
  • 使用union联合查询,手动创建临时表
  • 开启事务,维护数据库完整性
  • 使用外键,保证数据关联性
  • 使用索引,提高查询速度
  • 优化查询语句的书写

JVM内存

  • 堆、栈、方法区
  • 堆里主要存放各种实例对象,GC垃圾回收也主要在堆中进行
  • 栈里主要存放基本数据类型、方法引用、实例的方法

OOM

  • 堆内存满了,来不及GC垃圾回收,就会出现OOM故障,这个时候可以尝试增大JVM的堆内存。

  • Xms 设置初始化内存分配大小 默认电脑1/64

  • Xmx 设置最大分配内存 默认电脑内存1/4

  • XX:+PrintGCDetails:打印GC垃圾回收流程

  • XX:+HeapDumpOnOutOfMemoryError: Dump OOM

wait、notify

  • 在生产者消费者模型中用到
  • wait(),使当前线程等待。
  • 唤醒在此对象监视器上等待的单个线程,如果有多个线程同时在等待,那么就随机唤醒一个。

进程的状态

  • 进程全部可分为五种状态分别是:创建状态、就绪状态、运行状态、阻塞状态、终止状态。 在运行期间主要是三种状态:就绪、运行、阻塞状态。 需要知道进程几个状态转换的触发条件。

Java中有几种线程池,并详细描述一下线程池的实现过程

  • newCacheThreadPool:创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程。
  • newFixedThreadPool:创建一个指定工作线程数量的线程池,每当提交一个任务就创建一个工作线程,如果工作线程达到初始设置的最大数量,则将提交的任务存入池队列中
  • newSingleThreadExecutor:创建一个单线程化的Executor,即只创建唯一的工作者线程来执行任务,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。如果这个线程异常结束,会有另一个取代它,保证顺序执行。
  • newScheduleThreadPool:创建一个定长的线程池,而且支持定时的以及周期性的任务执行,支持定时及周期性任务执行。

逻辑地址和物理地址

  • 物理地址 = 页块×页表大小+偏移量(页内地址)
    页号 = 逻辑地址÷页表大小
    偏移量(页内地址) = 逻辑地址 mod 页表大小

段页式存储管理方式

  • 段页式存储管理方式. 段页式存储管理方式即先将用户程序分成若干个段,再把每个段分成若干个页,并为每一个段赋予一个段名。
  • 分为页号、页块,每页有页面大小

操作系统算法

  • 见本人博客专栏:Java实现操作系统算法
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yui方木

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值