Spring
- 说一说你对Spring的了解
- Spring是一个轻量级的Java开源框架,目的是为了解决在企业级应用开发过程中业务逻辑层和其他层的耦合性,Spring提供基础的框架,开发人员只需要专注于应用开发。
- Spring带来了哪些好处
- 基于POJO的轻量级和最小侵入性编程
- 控制反转/依赖注入将对象之间的依赖关系交给框架处理,降低了组件之间的耦合性
- AOP支持了一些通用任务,如事务、日志、安全、权限等集中管理,从而提供更好的复用
- 对主流框架提供了继承支持
- Spring的核心组件有哪些
- Spring core:提供IOC和DI技术支持,将对象之间的依赖管理交给Spring框架处理,降低对象之间的耦合性
- Spring AOP: 面向切面编程,通过动态代理对Spring管理的bead对象进行功能的增强,支持一些通用的任务,比如事务、安全、日志、权限等,提供更好的代码复用
- Spring Aspects:提供了强大的面向切片编程功能,可以对各种与对象的各种切入点进行编译前、编译后、加载时进行代码的织入
- Spring JDBC: 提供数据库的连接管理功能
- Spring ORM : 提供对象关系用设,将对数据库的操作封装,将字段映射到POJO对象上
- Spring Test:集合JUnit和TestNG测试框架
- Spring web:继承了web开发工具和开发框架
- Spring使用了哪些设计模式
- 工厂模式:Spring框架通过BeadFactory和ApplicationContext对bean对象的创建,注入和管理
- 代理模式:SpringAOP通过动态代理将通用业务代码织入到对应的bean对象中,提供事务、日志、安全、权限等功能
- 适配器模式:Spring web 接收到了请求后,DispatcherServlet会将请求发送给HandlerMapping中对应RequestMapping的Handler,然后使用HandlerAdpater对Handler进行转换,再调用统一的执行方法入口处理请求
- 模板模式:jdbcTemplate就是Spring提供的一种数据库操作模板
- 观察者模式:Spring的事件驱动应用了观察者模式,通过ApplicationEvent\ApplicationListener\ApplicationPublisher来完成时间的驱动
- 单例模式:Spring容器管理的bean默认是单例模式
操作系统
- 什么是内核态和用户态
- 内核态:运行操作系统程序,几乎可以访问所有的硬件资源
- 用户态:运行用户的应用程序
- 如何由用户态转换为内核态
- 系统调用
- 异常
- 硬件中断
- 程序和进程有什么关系
- 进程是计算机中一个独立程序对一个数据集合的一次运行,进程是系统资源分配和调度的基础,是操作系统的基础。程序是指令、数据以及对它们组织形式的描述,进程是程序的运行实体,是动态的。
- 什么是僵尸进程
- 僵尸进程就是指一个进程在调用exit命令退出之后,不会被销毁,而是保留一个叫僵尸进程的数据结构,这个数据结构没有任何可以执行的代码,不能倍调度,也几乎放弃了所有的内存空间,仅仅在进程列表中保留一个位置,此时需要父进程来回收这个空间,如果父进程没有回收并且退出,就会由init进程来回收,如果父进程一直循环并且没有回收,那么这个子进程就会一致保存僵尸状态
- 僵尸进程有什么危害
- 大量的僵尸进程会占用系统资源,而系统资源是有限的,当僵尸进程达到一定的数量,就会导致系统崩溃,因此编程的时候一定要避免产生僵尸进程
- 僵尸进程如何避免
- 父进程使用wait和waitpid函数等待子进程结束然后销毁
- 父进程使用signal函数为SIGCHILD信号天机handler
- 父进程不关心子进程的结束,直接交给操作系统处理
- 嗲用两次fork,杀死子进程,将孙进程交给init进程处理
- 什么是孤儿进程
- 当一个父进程先于子进程死亡时,这些子进程就叫做孤儿进程,这些孤儿进程会被init进程收养,init进程会检查和收集这些孤儿进程的状态信息,孤儿进程会被系统回收和销毁,而僵尸进程会占用系统id和资源,损害系统的运行
- 进程和线程之间的区别
- 一个进程可以产生多个线程
- 进程时资源分配的最小单位,线程时调度的最小单位
- 进程有独占的内存地址,线程共享进程的内存地址
- 一个进程切换的时候需要切换内存地址,开销大,但是更加健壮,进程之间互不影响
- 同一个进程的线程之间能够共享静态数据和全局变量,实现通讯
- 什么是协程,有什么优点
- 协程类似于轻量级的线程,不由操作系统内核控制,完全由程序进行控制
- 协程没有上下文切换的开销
- 单线程多协程的共享资源不用加锁
- 死锁产生的条件是什么
- 资源是互斥的,只有被一个进程占用和可用两种状态
- 当一个进程获取了一个资源之后,可以再请求其他的资源
- 资源是不能被剥夺的,一个进程请求另一个进程已经占有的资源,只能等待其自动释放
- 再系统中有存在由两个或者多个进程组成的环路,这个环路上每一个进程都在等待下一个进程释放资源
- 当多个进程之间占用了对方需要的资源,并且需要等到获取所有资源执行之后才能释放资源时,会产生死锁
- 死锁的避免方法
- 破解死锁产生的条件(占有一定数量的资源,抢占式获取,资源的超时释放,银行家算法等)
- 进程调度算法有哪些
- 先来先服务算法
- 最小运行时间算法
- 轮转法
- 优先级调度算法
- 多级反馈队列调度算法
- Java的线程调度方式
- 基于优先级的轮转抢占式调度
- 进程之间有哪些通讯方式
- 管道,信号量计数器,信号事件,消息队列,共享内存、本地套接字
- 线程之间有什么通讯方式
- 互斥量、信号量计数器,信号事件
- 说一说fork()函数
- 可以使用fork系统调用来创建一个和当前进程映像一样的子进程,创建成功返回子进程的pid,失败会返回一个负数
- 可以使用fork()函数结合exec()函数,将另外的二进制映像替换当前父进程的二进制映像,使得子进程执行另一个二进制可执行文件的映像
- 如何理解一次调用两次返回
- 在调用fork()系统调用创建子进程时,在子进程中fork函数返回0,在父进程中fork函数返回子进程的pid,可以通过返回值来区分父子进程,其实是在内存当中一个进程被复制成两个进程,分别被CPU执行,自然就会有两个结果
- IO模型的分类
- 同步和异步:消息通讯机制,同步为用户程序不断轮询,异步为内核通知
- 阻塞和非阻塞:用户在等在调用结果的状态,可以时阻塞状态,也可以是非阻塞状态
- select,poll,epoll之间的区别是什么
- 他们都是IO多路复用的实现函数
- select函数在调用时,用户会传入三种感兴趣的事件的socket描述符集合,分别是可读事件,可写事件和异常事件,每次调用select_wait来查找就绪的socket描述符,内核会将用户态中的描述符集合拷贝到内核空间,然后使用轮询的方式来检查socket是否就绪,最后如果返回0表示超时,返回-1表示失败,返回正常后用户程序再次轮询描述符集合来处理就绪的socket事件
- poll的实现机制和select类似,但是poll传入的文件集合不再分类,所有的都是用一个集合传入
- epoll使用过程中,用户使用epoll_create来创建一个epfp(epoll文件描述符),然后通过epoll_ctl来注册、修改、删除一个感兴趣的socket事件,当socket就绪时,内核就会激活这个socket,在用户调用epoll_wait时返回这个socket的文件描述符。epoll不需要轮询,因此事件复杂度为O(1),并且不仅只需要复制一次,还使用了内存映射机制,内核中和用户中文件描述符集合的虚拟空间都指向同一个物理空间,大大提高了性能和效率。