java八股文

该博客围绕Java技术展开,涵盖线程池、并发特性、JDK等基础知识,还涉及Spring、MyBatis等框架原理,以及数据库优化、消息队列等内容。同时介绍了设计模式、线程理解等实战要点,为Java开发者提供了全面的知识参考。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1线程池中提交一个任务得流程是怎样的

源代码

    public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
        /*
         * Proceed in 3 steps:
         *
         * 1. If fewer than corePoolSize threads are running, try to
         * start a new thread with the given command as its first
         * task.  The call to addWorker atomically checks runState and
         * workerCount, and so prevents false alarms that would add
         * threads when it shouldn't, by returning false.
         *
         * 2. If a task can be successfully queued, then we still need
         * to double-check whether we should have added a thread
         * (because existing ones died since last checking) or that
         * the pool shut down since entry into this method. So we
         * recheck state and if necessary roll back the enqueuing if
         * stopped, or start a new thread if there are none.
         *
         * 3. If we cannot queue task, then we try to add a new
         * thread.  If it fails, we know we are shut down or saturated
         * and so reject the task.
         */
        int c = ctl.get();
        if (workerCountOf(c) < corePoolSize) {
            if (addWorker(command, true))
                return;
            c = ctl.get();
        }
        if (isRunning(c) && workQueue.offer(command)) {
            int recheck = ctl.get();
            if (! isRunning(recheck) && remove(command))
                reject(command);
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
        else if (!addWorker(command, false))
            reject(command);
    }

2 线程池中有几种状态?分别是如何变化的?

状态:

1 RUNNING: 会接收新任务并且会处理队列中的任务

2 SHUTDOWN:不会接收新任务并且会处理队列中的任务,任务处理完后会中断所有线程

3 STOP: 不会接收新任务并且不会处理队列中的任务,并且会直接中断所有线程

4 TIDYING:所有线程都停止之后,线程池的状态会转为TIDYING,一旦达到此状态,就会调用线程池的terminated()

5 TERMINATED: terminated()执行完之后就会转变为TERMINATED

源码:

    private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
    private static final int COUNT_BITS = Integer.SIZE - 3;
    private static final int CAPACITY   = (1 << COUNT_BITS) - 1;

    // runState is stored in the high-order bits
    private static final int RUNNING    = -1 << COUNT_BITS;
    private static final int SHUTDOWN   =  0 << COUNT_BITS;
    private static final int STOP       =  1 << COUNT_BITS;
    private static final int TIDYING    =  2 << COUNT_BITS;
    private static final int TERMINATED =  3 << COUNT_BITS;

3 如何优雅的停止一个线程

stop():stop()会释放线程占用的synchronized锁,而不会自动释放ReentranLock锁

interrupt(): 该方法只是在目标线程中设置一个标志,表示它已经被中断,线程是否中断,取决于线程本身,

4 线程池的核心线程数,最大线程数如何设置?

对于cpu密集型任务:                    cpu核心数+1

                 io型任务:                     2*cpu核心数

                                                       cpu核心数 * (1 + 线程等待时间 / 线程运行总时间 )

                                                                               可以使用jvisualvm来估算这两个时间

corePoolSize: 核心线程数,表示线程中的常驻线程个数

maximumPoolSize: 最大线程数,表示线程池总能开辟的最大线程个数

核心应用():核心线程数 = maximumPoolSize = 压测出来的个数,

非核心线程:核心线程数设置少点,maximumPoolSize=压测个数

5 如何理解java并发中的可见性

 java 并发可见性是指多线程并发访问共享变量时,对变量的更改能够被其他线程及时感知                                                   

 可以使用volatile关键字来保证变量的可见性

6 如何理解Java并发中的原子性?

线程在执行一段代码的时候,要么全部执行成功,要么全部不执行,不能执行到一半就结束了

java里面通过各种锁机制来保证原子性

7 如何理解Java并发中的有序性

java并发有序性指的是多个线程执行的指令和操作,按照开发者编写程序的顺序或预定的顺序进行执行。多线程并发执行时,可能会发生指令的重排,导致程序的执行顺序与预期不一致,从而出现数据竞争和线程安全问题

8JDK JRE JVMM之间的关系

JDK : java标准开发包,他提供了编译,运行Java程序所需的各种工具和资源,包括java编译器,            java运行时环境,以及常用的java类库等

JRE:java运行环境,用于运行java的字节码文件

JVM:JAVA虚拟机,是jre的一部分,他是整个java实现跨平最核心的部分,负责运行字节码文件

9 hashCode()和 equals()之间的关系

在java的一些集合类的实现中,在比较两个对象是否相等时,会先调用对象的hashCode()方法得到hashCode进行比较,如果hashCode不相同,就可以认为这两个对象不相同,如果hashcode相同,就会调用equals方法进行比较

10 String StringBuffer StringBuilder的区别

1 String是常量不可变,StringBuilder StringBuffer是可变的

2 StringBuilder线程不安全,StringBuffer线程安全

11 泛型中extends和super的区别

12==和equals的方法区别

13ArrayList和LinkList有哪些区别

14CopyOnWriteArrayList底层原理

15HashMap的扩容机制

16ThreadLocal的底层原理

17如何理解volatile关键字

保证了并发领域的可见性和有序性(内存屏障),对于加了volatile关键字的属性,会直接将cpu高级缓存中的数据写回主内存,对于这个变量的读取,也会从主内存中读取

18ReentrantLock中的公平锁和非公平锁的底层实现

底层使用AQS进行排队

公平锁 加锁时会检查AQS队列中是否存在线程在排队,如果有线程在排队,则当前线程也进行排队

非公平锁: 不会检查是否有排队,而是直接竞争锁

ReentranLock是可重入锁

19ReenTrantLock中tryLock()和lock()方法的区别

tryLock():尝试加锁,有返回值,非阻塞,可以用来设计自选锁

lock:没加到锁会阻塞,无返回值

自旋锁:比较消耗cpu

20 CountDownLatch和Semaphore的区别和底层原理

CountDownLatch表示计数器,可以给CountDownLatch设置一个数字,一个线程调用CountDownLatch的await()将会阻塞,其他线程可以调用CountDown()方法对CountDownLatch中的数字减一,当数字减少到0后,所有await的线程都将被唤醒。

Semaphoore表示信号量,可以设置许可的个数,表示同时允许最多多个线程使用该信号量,通过acquire()来获取许可,如果没有许可可用线程阻塞,并通过AQS来排队,可以通过release()方法来释放许可,当某个线程释放了某个许可后,会从AQS中正在排队的第一个线程开始依次唤醒,知道没有空闲许可。

21 Sychronized的偏向锁,轻量级锁,重量级锁

1 偏向锁: 在锁对象的对象头中记录下当前获取到该锁的线程ID,该线程下次如果又来获取该锁就可以直接获取到了

2 轻量级锁: 由偏向锁升级而来,当一个线程获取到锁后,此时这把锁是偏向锁,此时如果第二个线程来竞争锁,偏向锁就会升级为轻量级锁,之所以叫轻量级锁,是为了和重量级锁区分开,轻量级锁底层是通过自旋实现的,并不会阻塞线程

3 如果自旋次数过多任然没有获取到锁,则会升级称为重量i就锁,重量级锁会导致线程阻塞

4 自旋锁 自旋锁是线程在获取锁的过程中,不会去阻塞线程,也就无所谓唤醒线程,阻塞和唤醒这两个步骤都是需要操作系统中进行的,比较消耗时间,自旋锁是线程通过CAS获取预期的一个标记,如果没有获取到,则会继续循环后去,如果获取到了则表示获取到了锁,这个过程线程一致在运行中,想对而言没有使用泰索的操作系统资源,比较轻量

22 Sychronized和ReentLock的区别

1 Sychronized是关键字,ReentLock是一个类

2 sychronized会自动加锁和释放锁,ReentrantLock需要程序员手动加锁与释放锁

3 sychronized的底层是JVM层面的锁,ReentranLock是API层面的锁

4 sychronized是公平锁,ReentrantLock可以选择公平锁或非公平锁

5 sychronized锁是对象,锁幸喜保存在对象头中,ReentrantLock通过代码中的int类型的state标识来标识锁的状态

6 sychronized底层有一个锁升级的过程

23线程池的工作原理

线程池内部是通过队列+线程实现的,当我们利用线程池执行任务时:

1 如果此时线程池中线程的数量小于corePoolSize,即使线程池中的线程都础语空闲的状态,也要创建新的线程来处理被添加的任务

2 如果此时线程池中的线程数等于corePoolSize,但是缓冲队列workQueue未满,那么任务被放入缓冲队列中

3 如果此时线程池中的线程数量大于等于corepoolSize缓冲队列workQueue满,并且线程池中的数量小于maxmumPoolSize,建新的线程来处理被添加的任务

4 如果此时线程池中的线程数量德语corePoolSize,缓冲队列满了,并且线程池中的数量等于maximumPoolSize,那么通过handler所指定的策略来吃力此任务

5 当线程池的线程数量大于corePoolSize时,如果某线程的空闲时间超过keepAliveTime,线程将被停止,这样线程池可以动态地调整池中地线程数

24 JVM中哪些是线程共享区

堆区和方法区是共享的,栈,本地方法栈,程序计数器是每个线程独有的

25 JVM中哪些可以作为gc root

26你们的项目如何排查JVM问题

27 说说类加载器双亲委派模型

28 Tomcat中为什么要使用自定义类加载器

29 Tomcat如何进行优化

30 浏览器发出一个请求到收到响应经历了哪些阶段

31 跨域请求是什么?有什么问题如何解决

跨域是指浏览器在发起网络请求的时候,会检查该请求所对应的协议,域名端口和当前网页是否一致,不一致浏览器就会进行限制

解决:

        1 response添加header,比如 resp.setHeader("Access-Control-Allow-Origin","*")表示可以访问所有网站,不受是否同源的限制

        2 jsonp 的方式,script标签是可以跨域的

        3 后台自己控制,先访问同域名下的接口,然后再接口中再去使用HttPClient工具去调用目标接口

        4 网关,交给后台服务来进行跨域访问

32 Spring中Bean创建的生命周期有哪些

1 推断构造方法

2 实例化

3 填充属性,也就是依赖注入

4 处理aware回调

5 初始化前 ,处理@PostConstruct注解

6初始化,处理InitializingBean接口

7初始化后,进行AOP

33 Spring中Bean是线程安全的吗

Spring本身并没有针对Bean做线程安全的处理,所以:

        1.如果Bean是无状态的,那么Bean则是线程安全的

        2 如果Bean是有状态的,那么Bean则不是线程安全的

        bean是不是线程安全跟作用域没有关系,Bean的作用域只是表示Bean的生命周期范围

34 ApplicationContext和BeanFactory有什么区别

BeanFactory是Spring中非常核心的组件,表示Bean工厂,可以生成Bean,ApplicationContext继承BeanFactory,拥有BeanFactory的所欲特点,也是一个Bean工厂,但是Applicationcontext还继承了EnvironmentCapable,MessageSource,ApplicationEventPulisher等接口,从而Applicationcontext还有获取环境变量,国际化,时间发布等功能

35 Spring中的额事务是如何实现的

1 spring事务底层时基于数据库事务和AOP机制实现的

2 首先对于使用了@Transational注解的Bean,Spring会创建一个代理对象作为Bean

3 当调用代理对象的方法是,会判断该方法上是否加了@Transactional注解

4 如果加了,那么则利用事务管理器创建一个数据库连接

5并且蟹盖数据库连接的autocommit属性为false,禁止此连接自动提交

6 然后执行当前方法,方法中会执行sql

7 执行完当前方法后,如果没出现异常就直接条事务

8如果出现了异常,并且这个异常时需要回滚的就会回滚事务,否则任然提交事务

9 Spring事务的隔离级别对应的就是数据库的隔离级别

10 Spring事务的传播机制是Spring事务自己实现的,也是Spring事务中最复杂的

11 Spring事务的传播机制是基于书库连接来做的,一个是数据库连接一个事务,入股偶传播机制配置为需要新开一个事务,那么实际上就是先及案例一个数据库连接,再次新数据库连接上执行sql

36 spring中什么时候@Transactional会失效

Spring中的事务是基于代理实现的,所以某个加了@Transactional 的方法只有是被代理对象调用时,那么欸这个注解才会生效,如果是被代理对象来调用这个方法,@Transactional是不会失效的

同时某个方法是private,那么@Transactional也会失效,应为底层cglib是基于父子类来实现的,子类是不能重载父类的private方法的,所以无法很好的利用代理,也会导致@Transactional失效

37Spring容器启动流程是怎样的

1 在创建Spring容器,也就是启动Spring 时:

2 首先会进行扫描,扫描所得到的所有BeanDefinition对象,并存在一个Map中

3 然后筛选出非懒加载的单例BeanDefinition进行创建Bean,对于多礼Bean不需要再启动过程中去进行创建,对于多礼Bean会在每次获取Bean时利用BeanDefinition去创建

4 利用BeanDefinition创建Bean的创建生命周期,这期间包括了合并BeanDefinition推断构造方法,实例化,属性填充,初始化前,初始化,初始化后等步骤,其中AOP就是发生载初始化后这一步骤中

5 单例Bean创建完了之后,Spring会发布一个容器启动事件

6 Spring启动结束

7 在源码中会跟复杂,源码中提供了一些模板方法,让子类实现

8 在Spring启动过程中还会去处理@Import等注解

38 Spring用到了哪些设计模式

工厂模式:BeanFactory FactoryBean

适配器模式: AdvisionAdapter 接口,对Advision进行了适配

访问者模式:PropertyAccessor接口,属性访问问题,用来访问和设置莫格对象的某个属性

装饰器模式:BeanWrapper

代理模式:AOP

观察者模式:事件监听

策略模式:InstantiationStrategy

模板模式:JdbcTemplate

委派模式:BeanDefinitioonParserDelegate

责任链模式:BeanPostProcessor

39 SpringMVC的底层工作原理

1 用户发送请求至前端控制器DispatcherServlet

2 DispatcherServlet收到请求调用HandlerMapping处理器映射器

3 处理器映射器找到具体的处理器,生成处理器及拦截器一并返回给DispatcherServlet

4 DispatcherServlet调用HandlerAdapter处理器适配器

5 HandlerAdapter经过适配调用具体的处理器(C哦那troller,也叫后端控制器)

6 Controller执行完后返回ModelAndView

7 HandlerAdapter将controller   执行结果ModelAndView返回给DispatcherServlet

8. DispatcherServlet将 ModelAndView传给ViewReslover视图解析器。

9.ViewReslover解析后返回具体View。
10.DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)。11.DispatcherServlet响应用户。

40 Springboot中常用的注解及底层实现

1 @SprigBootApplication注解:这个注解标识了一个Springboot工程,由三个注解组合

   a.@SpringBootConfiguration:这个注解实际就是一个@Configuration,表示启动类也是一个配置类

   b.@EnableAutoConfiguration:向Spring容器中导入了一个Selector,用来加载ClassPath下的SpringFactories中所定义的自动配置类,将这些自动加载为配置Bean

    c.@ComponentScan:标识扫描路径

2  @Bean注解:用来定义Bean类似于XML中的<bean>标签,Spring在启动时,会对加了@Bean注解的方法进行解析,将方法的名字作为beanName,  并通过执行方法得到Bean对象

3 @Controller @Service @ResponseBody @Autowired 

41 SpringBoot是如何启动Tomcat的

1 首先,SpringBoot在启动时会先创建一个Spring容器

2 在创建Spring容器过程中,会利用@ConditionalOnClass技术判断当前classpath中是否存在Tomcat依赖,如果存在则会生成一个启动Tomcat的Bean

3 Spring容器创建完,就会创建Tomcat 的Bean,然后创建Tomcat对象,绑定端口等,启动Tomcat

42 SpringBoot中配置文件的加载顺序是怎么样的?

1 命令行参数

2 Java 系统属性

3 操作系统环境变量

4 先jar包外部后jar包内部,先带profile,后不带profile

5 @Configuration注解类上的@PropertySource

43 Mybatis存在哪些优缺点

1 相当灵活,基于SQL语句编程,不会对应用程序和数据库设计造成影响,解耦,接触程序代码和sql语句的耦合

2 于jdbc相比,代码量减少50%以上,不需要手动关闭连接

3 很好的与各种数据库兼容

4 能够与spring很好的集成

5 提供映射和关系映射标签

44 Mybatis中#{} ${}的区别是什么?

1 #{}是占位符, ${}是字符串替换,拼接符

2 Mybatis会将#{}替换为?,调用PrepareStatement来赋值

3 Mybatis在处理${}时,就是把${}替换成变量的值,调用Statement来赋值

4 使用#{}可以用小的防止SQL注入,提高系统的安全性

45 什么是CAP理论

分布式领域的一个重要论

C:表示强一致性

A:表示可用性

p:分区容错性

一个分布式系统是必须要保证分区容错性的,分布式系统要么cp,要么ap

分区容错性表示:系统虽然是分布式的,但对外看上去应该是一个整体,

可用性:一个分布式系统要保证对外可用

强一致性表示;一个分布式系统中各个节点之间能及时同步数据,在同步数据的过程中,是不能对外提供服务的

46 什么是BASE理论

1 BA: 表示机泵可用,允许在一定程度上不可用

2 S:Soft state:表示分布式系统处于一种中间状态

3 E: 表示最终一致,不要求数据实时一致允许数据经过一段时间后达到一致,在达到一致的过程中,系统是可用的

47什么是RPC

RPC,表示远程过程调用,对于java这种面向对象的语言也可以理解为远程方法调用,是一种远程调用方法的方式

RPC可以使用Http协议实现也可以使用TCP实现

RPC协议是HTTP之上的一种协议

48 分布式ID是什么?有哪些解决方案?

分布式系统中标识数据的唯ID,单体系统中可以使用数据库自增id,内存中自增数字作为唯一id ,但分布式系统中不行

解决方案:

1 uuid,复杂度低,但会影响存储空间和性能

2 使用单机数据库的自增主键,复杂适中,id较uuid短,不适合并发量大的时候

3 使用redis的自增命令,zookeeper的自增节点,较2性能有所提升,适当选用

4 雪花算法,底层是某台机器在某一毫秒内对某个数字自增

49 分布式锁的应用场景?有哪些实现方案?

应用场景:不同进程的线程并发执行时遇到资源竞争,需要一个分布式锁生成器生成锁,达到多个进程中的线程使用同一把锁

实现方案:

zookeeper: 利用zookeeper的临时节点,顺序节点,watch机制实现,保证了cp

redis: 利用redis的setnx,lua脚本,消费订阅机制实现,保证了AP,缺点:可能出现数据不一致的问题

50什么是分布式事务,有哪些实现方案?

在分布式系统中,一次业务可能需要多个应用实现

实现方案:

1 本地消息

2 消息队列

3 Seata

51 什么是ZAB 协议

是zookeeper实现一致性的原子广播协议,描述了zookeeper如何实现一致性的:

实现分为三个阶段:

1 领导者选举阶段:在zookeeper集群中选举一个leader,所有写请 由leader处理

2 数据同步阶段:集群中所有节点要和leader保持一致

3 请求广播阶段:当leader节点收到写请求时,广播请求,达到节点上的数据一实时一致性

zookeeper只是尽量达到数据一致性,但任是最终一致性

52 为什么Zookeeper可以用来作为注册中心

利用Zookeeper的临时节点和watch机制实现自动注册和发现,数据存在内存中,再用nio,多线程模型,性能高,zookeeper使用的是cp

53 Zookeeper中领导者选举流程是怎么样的

1 观望投给自己

2 交换投票比较,先比较zxid,相等再比较myid

3 输 投给更大的节点,把选票投到自己节点和发送给其他节点

  平局 接收到的选票放入自己投票箱中

  赢 不接受收到选票

4 收到选票,统计,看超过一半节点和自己所投节点是否一致,一致,自己所投节点是leader

5 zookeeper集群中节点之间数据是如何同步的

54 Zookeeper集群中节点之间的数据是如何同步的

1 集群启动,领导者选举,确定哪个是leader,follower observer

2  leader和其他节点进行数据同步,采用发送快照和diff日志的方式

3 leader处理写请求,从节点处理读请求

4Leader节点收到一个写请求时,会通过两阶段机制处理

5 leader将写请求日志发送给Follower节点,等待Follower节点持久化日志成功

6 Follower节点持久化日志成功会发送一个ack给leader

7 leader收到半数以上的ACK 后,先更新本地内存数据再更新Follower,

8 同时leader  在收到写请求时,会把写请求发发送给observe,observe收到写请求,会更新自己的内存和数据

10 最后leader向客户端返回响应成功

11 通过同步机制和两阶段提交机制来达到集群中节点数据一致

55 Doubbo支持的负载均衡策略

1 随机: 从多个服务提供者中选择一个来处理当前情趣,调用量越大,分布越均匀,并支持按权                 重 设置随机概率

2 轮询: 依次选服务提供者来处理请求,支持权重轮询,底层采用平滑加权算法

3 最小活跃调用次数: 统计服务提供者当前正在处理的请求,下次请求交给活跃数最小的服务器处理

4 一致性哈希: 相同参数的请求总是发送到同一个服务提供者

56 Doubbo是如何完成服务导出的

56 Doubbo如何完成服务导出

1 解析@Doubboservice和@Service 得到一个ServiceBean

2 然后调用ServiceBean的export导出

3 将服务信息注册到注册中兴

4 绑定监听器

5 启动对应的web服务框架,tomcat,netty等

57 Doubbo是如何完成服务引入的?

1 @Reference来引入一个服务,Doubbo会将注解和服务信息解析出来,得到所引用的服务名,服务接口

2 在注册中心查询服务信息,得到服务的提供者信息,并存到消费端

3 绑定监听器来动态监听配置中心得变更

4 更据查询得到得服务提供者信息生成一个服务接口代理对象,并放入Spring容器中作为Bean

58 Doubbo的架构设计是怎样的

架构有很多层,每层都是可扩展的:

1 Proxy服务代理层

2 Register注册中心层

3 Protocol远程调用层

4 Transport网络传输层

5 Seralize数据序列化层

59 Spring Cloud有哪些些常用组件,作用是什么

1 Eureka:注册中心

2 Nacos: 注册中心,配置中心

3 Consul: 注册中心,配置中心

4 Spring Cloud Config:配置中心

5 Feign/OpenFeign:RPC调用

6 Kong:  服务网关

7 Zuul:服务网关

8 Spring Cloud Getway: 服务网关

9 Ribbon:负载均衡

10 Spring Cloud Sleuth:链路追踪

11 Zipkin: 链路追踪

12 分布式事务

13 Doubbo: RPC调用

14 Sentinel:服务熔断

15 Hystrix:服务熔断

60 Spring Cloud和Doubbo有哪些区别

Spring Coud是一个大而全的微服务框架

Doubbo 是一个RPC调用框架,侧重调用

Doubbo和spring cloud并不冲突,可以结合在一起使用

61 什么是雪崩?什么是服务限流?

1 A请求调用B请求,B请求调用C请求,当大量请求过来,A能抗住,C不能抗住,导致c请求大量堆积,b请求堆积,从而导致A请求不可用,这就是服务雪崩,解决方式是服务降级和服务熔断

2 服务限流是指在高并发的请求下,为了保护系统,可以对访问服务器的请求进行限制,保护系统不会被大量请求压垮

62 什么是服务熔断?什么是服务降级?区别是什么?

1 服务熔断:当a调用b,b不可用,a保证自己不受影响,不在调用b,直接返回一个结果,减轻a和b的压力,直到b可用

2 服务降级: 当系统压力过载时,就会关闭或限流某个服务,减轻系统压力

63 SOA,分布式,微服务之间的关系和联系?

1 分布式架构是将单体架构的各个部分拆分,部署到不同的机器或线程上去,SOA和微服务都是分布式架构

2 SOA是一种面向服务的架构

3 微服务是一种更加彻底的面向服务的架构

64 BIO NIO AIO分别是什么

BIO:同步阻塞IO,BIO读取数据时线程会阻塞,需要线程主动查询是否有数据可读,处理完一个soket后才能处理下一个socket

NIO:同步非阻塞io,使用NIO读取数据时线程不会阻塞,但需要去查询是否欧io时间

AIO:异步非阻塞,读取数据时不会阻塞,当有可读数据时会通知给线程

65 零拷贝是什么

用户在把内核的一块数据区域转移到另外一块区域时,不需要经过赋值到用户空间,再转移到目标内核区域,而直接实现转移

66 Netty是什么,n和tomcat有什么区别,特点是什么?


Netty是基于NIO的异步网络通信框架,性能高,用来开发各种网络服务器

Tomcat是一个网络服务器,内部只运行servlet,并处理HTTP请求,而Netty封装的是底层IO模型,关注的是网络数据传输,不关注具体协议

netty的特点是什么:

1 异步,NIO 网络通信框架

2 高性能

3 高扩展,高定制性

4 易用性

67 Netty的线程模型是怎么样的

Netty同时支持Reactor单线程模型,Reactor多线程模型,Reactor主从多线程模型,用户可以根据启动参数配置在这三种模型之间切换

68 Netty的高性能体现在哪些方面

1 NIO模型,用更少的资源做更多的事情

2 内存零拷贝

3 内存池设计

4 串行化处理读写

5 高性能序列化协议

6 高效并发编程体现

69 Redis有哪些数据结构?分别有哪些典型应用场景?

1 字符串:分布式锁 计数器 Session共享 分布式id

2 哈希表:存储kv键值对

3 列表:可以当栈也可以当队列,缓存消息流数据

4 集合:不能重复,实现共同关注,朋友圈点赞

5 有序集合:有顺序,可以实现排行榜

70  Redis分布式锁是如何实现的

1 利用setnx来办证:key不存在才能获取到锁

2 利用lua脚本来保证多个redis操作的原子性

3 考虑锁过期,需要额外的定时任务来监听是否需要续约

71 Redis主从复制的核心原理

1 集群启动时主从库会建立连接,为全量复制做准备

2 主库将所有数据同步给从库,从库收到数据后,完成本地数据加载,依赖内存快照RDB

3 主库将数据同步给从库的过程中不会阻塞,任然可以接收请求

4 第三阶段,主库把收到的写命令发送给从库

5 后续主库和从库都可以处理客户端读操作,写操作只能交给主库处理

72 缓存穿透,缓存击穿,缓存学蹦分别是什么

1 缓存雪崩:如果缓存中某一时刻大批量热点数据同时过期,那么就可能导致大量请求直接访问Mysql,解决办法是在过期时间上增加一点随值,搭建一个高可用Redis集群也是防止缓存雪崩的有效手段

2 缓存击穿:某一个热点key突然失效,导致大量请求直接访问Mysql,解决,热点key不设置过期时间

3 缓存穿透:假如某一时刻访问redis的大量key都在redis中不存在,会给数据造成大量压力,使用布隆过滤器来拦截不存在的key

72 Redis和Mysql如何保证数据一致

延迟双删:先删除Redis缓存数据,再更新Mysql,延迟几百秒再删除缓存

73 Explain语句中各个字段分别表示什么意思

id: 查询语句每出现一个select,Mysql就会为其分配一个唯一ID,某些子查询会被优化为join查询,那么出现的id会一样

select_type:SELECT对应的那个查询类型

table: 表名

partitions:匹配的分区信息

type:争对单表的查询方式(全表扫描,索引)

possible_keys:可能用到的索引

key: 实际上用到的索引

key_len:实际使用到的缩影长度

ref: 当使用索引列查询时,与索引列进行等值匹配的对象信息

rows: 预估需要的去的记录条数

filtered: 某个表经过搜过条件过滤后剩余记录条数的百分比

Extra:一些额外信息,比如排序

74 索引覆盖是什么

索引覆盖是指sql执行时,利用索引快速查找,,并且此sql要查询的字段在当前索引对应的字段都包含了,此sql走完索引就不用回表了,所需的字段都在当前索引的叶子节点存在,可以直接作为返回结果

75 最左前缀原则是什么

当一个sql 想要利用索引时,那么就一定要提供该索引所对应字段中的最左边字段

76 Innodb是如何实现事务的

Innod通过Buffer Pool log,Buffer ,redo log,undo log来实现事务的

77B树和B+树的区别,为什么说Mysql使用B+树

B树的特点:

1 节点排序

2 一个节点可以存多个元素,多个元素也排序了

 B+树的特点:

1 拥有B树的特点

2 叶子节点之间有指针

3 非叶子节点上的元素在叶子节点上冗余了,也就是叶子节点中存储了所有的元素,并且排好顺。

Mysql索引使用的是B+树,可以加快查询,一个节点可以存多个元素,B+树高度不会太高,一个Innodb页就是一个B+树节点,一个 Innodb 页默认16kb,所以一般情况下两层的B+树可以存2000万行数据

可以支持全表扫描,范围查询等Sql 语句

78 Mysql锁有哪些,如何理解

按锁力度分:

1 行锁,锁某行数据,锁粒度小,并发高

2 表锁: 锁整张表,锁粒度最大,并发低

3 间隙锁:锁某个区间

还可以分为:

1 共享锁:也就是读锁,给某行数据加了读锁,其他事务也可以读,但不能写

2 排他锁: 写锁,给某行数据加了写锁,其他事务不能读,也不能写

还可以分为:

1 乐观锁: 并不会真正的锁某行数据,而是通过某一个版本号实现

2 悲观锁:行锁,表锁都是悲观锁

79 Mysql慢查询如何优化?

1 检查是否走了索引,如果没有则优化SQL利用索引

2 检擦利用的索引是否是最优索引

3 检查所查字段是否都是必须的

4 检查表中数据是否过多,是否应该进行分库分表

5检查数据库所在机器的配置性能,适当增加资源

80 消息队列有哪些作用

1 解耦:使用消息队列来作为两个系统直接的通讯方式,两个系统不需要相互依赖

2 异步:系统A给消费队列发送完消息之后,就可以做其他事情了

3 流量削峰:人如果使用消息队列的方式调用某个系统,那么消息在某个队列中排队,由消费者自己控制消费速度

81 死信队列是什么,延时队列是什么?

1 死信队列也是一个消息队列,存放没用消费成功的消息,通常可以用作消息重试

2 延时队列就是用来存放在指定时间需要被处理的元素的队列,处理一些具有过期性操作的业务

82 Kafka为什么比RocketMq的吞吐量高

kafka生产者采用异步发送消息的机制,消息发送先缓存起来,达到一定数量,再批量发送给Broker,减少了网络io,生产者宕机会导致数据丢失,这样做提高了性能,降低了可靠性

83 Kaflka的push和Push分别什么优缺点

1 push表示消费者主动拉去,可以批量拉去,也可以单条拉取,但有可能拉去到空消息

2 push表示Broker给消费者推送消息,所以肯定是有消息才推送,推送多少消息,消费者消费多少消息,可能会造成网络堵塞

84 RocketMq的底层实现

RocketMQ由NameServer集群,Producer集群,Conssumer集群,Broker集群组成

1 Broker在启动的时候向所有NameServer注册,保持长连接

2 Producer在发送消息的时候从NameServer获取Broker服务地址,根据负载均衡算法向一台服务器发送一条信息

3 Consumer消费信息的时候同样从NameServer中获取Broker地址,然后主动拉取信息消费

85 消息队列如何保证消息可靠传输

消息可靠传输代表:既不能多也不能少

1 生产者不能重复生产消息,消费者不能重复消费消息,保证消息不多

2保证消息不多发,需要在消费端做控制

3 避免不重复消费,消费者实现幂等性

4 消息不能少,生产者发送消息时,确认broker收到并持久化了这条消息(RabbitMQ的confirm机制,Kafka ack机制),broker要等消费者收到了消息才删除调消息,通过消费端的ack 机制实现

86 TCP的三次握手和四次挥手

TCP是7层网络协议中的传输层协议,负责数据的可靠传输

在建立tcp连接时,需要通过三次握手建立:

1 客服端向服务端发送一个SYN

2 服务端接收到SYN后,向客服端发送一个SYN_ACK

3 客服端接收到SYN_ACk 后向服务端发送一个ACK

在断开TCP连接时需要通过四次挥手来断开:

1 客服端向服务器发送FIN

2 服务端接收到FIN后向客服端发送ack,表示我接受到断开连接的请求,客户端可以不发送数据了,不过服务端可能还有数据在处理

3 服务端处理完所有数据后,向客户端发送FIN,表示服务端现在可以断开连接了

4 客户端收到服务端哦的fin,向服务端发送ACK,表示客服端断开连接了

87 java中创建线程的几种方式

1 继承Thread 类,重写run方法

2 实现了Runnable接口,实现run方法

集合篇

java 提供的集合:

Collection:

        list(有序可重复):        

                Vector-----数组结构,线程安全

                ArrayList----数组结构,非线程安全

                LinkList----链表结构,非线程安全

        set(无序,唯一)

                HashSet-----哈希表结构

                TreeSet  ----红黑树结构

Map:

        map(双列集合)

                HashTable: 哈希表结构,线程安全----Properties

                HashMap: 哈希表结构,非线程安全----LinkedHashMap 哈希表和链表结构

                ConcurrentHashMap 哈希表结构,线程安全

                TreeMap    红黑树结构

1 算法复杂度分析

时间复杂度:代码的执行耗时

        大O表示法:不具体表示代码的真正执行时间,而是表示代码执行时间随数据规模增长趋势的变化

空间复杂度;代码运行所需要占用的内存空间

2 List相关面试题

1 数据结构-数组

添加删除:o(n)

查询:

        已知索引:o(1)

        未知索引o(n)

2 ArrayList源码分析

成员变量:

构造函数:

关键方法:

添加:

第一次添加数据:

扩容:

3 ArrayList底层实现原理

底层数组实现,每次扩容是以前的1.5倍,每次扩容会复制原来的数组,初始容量为0,第一次添加数据时容量为10,添加数据时,检查使用长度+1是否能存下一个数据,就会先计算容量,容量不够,调用grow方法进行扩容,新增数据有地方存了之后,放到size这个地方,放回成功布尔值

4 如何使用数组和List之间的转换

aslist是对象的应勇,tolist是数组的拷贝

5 链表操作数据的时间复杂度

6  ArrayList和LinkList的区别是什么

1 底层数据结构

        Arraylist是动态数组实现的

        LinkList是双向链表实现的

2 操作效率

        ArrayList按照下标查询的时间复杂度0(1)

        未知索引:

                Arraylist和linkList都是 o(n)

        新增和删除

          Arraylist尾部删除和插入,时间复杂度是O(1),其他是O(n)

          LinkList头尾节点增删是o(1),其他o(n)

3 内存空间的占用:

        arrayList:内存连续,节省内存

        LinkList: 双向链表,有两个指针,更占用内存

4 线程安全

都是线程不安全的·

解决:

方法内使用,局部变量则是线程安全

使用线程安全的ArrayList和Linklist

使用Collection.synchronizedList()方法包装

3 HashMap相关面试题

1 二叉树:每个节点最多有两个子节点

        1二叉搜索树:左节点都要小于又节点,插入删除查询o(log(n))

        2 红黑树 :节点要么是红色,要么是黑色,叶子节点是黑色空节点,红色节点的子节点是黑色,任意节点到子节点经过的黑色节点相同

                1红黑树的时间复杂度,查找删除添加是o(log(n))

2 散列表

        概念:是更据键访问内存存储位置值的数据结构,由数组演变而来

        散列函数:将key映射为数组下标的函数叫散列函数,可以表示为hashValue=hash(key)

                 要求:散列函数必须是大于0的正整数,key相同散列值相同,key不相同,散列值也不相同

        hash冲突:多个key 存映射到了相同位置,解决办法:

                        拉链法:将链表法中的改造改造为红黑树效率更高,查找和删除o(log(n))

3 HashMap的实现原理

        数据结构:hash表的数据结构,数组加链表或红黑树

        放元素时:

                1 利用key的HashCode重新hash计算出当前对象的元素在数组的下标。

                如果hash值相同:

                        key 相同:覆盖

                        key不同:key-value放入链表或红黑树(当链表长度大于8,数组长度大于64,转为红黑树)

                2 获取值,找到hash值对应的下标,进一步判断key是否相同,从而找到对应值

4 HashMap的jDK1.7和jdk1.8有什么区别

        

jdk1.8之前采用的是拉链法:将链表和数组结合。遇到hash冲突直接将冲突的值加到链表中

jdk1.8之后遇到hash冲突,当数组长度大于64,链表长度大于8,转化为红黑树,减少搜索空间。扩容时,红黑树拆分程的树节点小于等于6,退化为链表

5 Hash的put方法的具体流程

默认容量值为16 ,加载因子为0.75,扩容阈值==数组容量*加载因子

6 HashMap的扩容机制

7 hashMap的寻址算法
8 hashmap在1.7情况下的多线程死循环问题

数据库篇

Mysql-优化

1 定位慢查询

方案一:

调试工具:Arthas

运维工具: Promethus,Skywalking

方案二:Mysql 自带慢日志

慢查询日志记录了所有执行时间超过指定参数(long_query_time,单位:秒,默认10秒)的所有SQL语句的日志,如果要开启慢查询日志吗,需要在Mysql的配置文件(/etc/my.cnf)中配置如下信息

Redis篇

缓存穿透:

查询一个不存在的数据,mysql查询不到数据也不会直接写入缓存,就会导致每次请求都查询数据库

框架篇

Spring框架中的bean是线程安全的吗?

spring框架中的bean默认是单例的

不是线程安全的

Sping框架中有一个@Scope注解,默认值就是singleton,单例的

因为一般在spring中的bean都是注入无状态的对象,没有线程安全问题,如果在bean中定义了可修改的成员变量,是要考录线程安全的

可以使用多例或加锁解决

什么是aop?

aop称为面向切面编程,用于将哪些与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可重用的模块,这个模块被命名为切面(Aspect),减少系统中的重复代码,降低了模块间的耦合度,同时提高了系统的可维护性

常见的aop的使用场景?

1 记录操作日志

2 缓存处理

3 spring中内置的事务处理

 spring中事务失效的场景?

异常捕获处理

抛出检查异常

非public方法

Spring的bean的生命周期?

1 通过BeanDefinition获取bean的定义信息

2 调用构造函数实例化bean

3 bean 的依赖注入

4 处理Aware接口(BeanNameAware,BeanFactory,ApplicationAware)

5 Bean的后置处理器BeanPostProcessor-前置

6 初始化方法(InitalizingBean,init-method)

7 Bean的后置处理器BeanPostProcessor-后置

8 销毁bean

Spring中的循环引用

Spring解决循环依赖是通过三级缓存

SpringMvc的执行流程

1 视图版本

2前后端接口开发

Springboot的自动配置原理

@SpringbootApplication包括:

@SpringBootConfiguration:该注解与@Configuration注解作用相同,来声名当前也是一个配置类

@ComponentScan:组件扫描,默认扫描当前引导类所在的包及其子包

@EnableAutoConfiguration:SpringBoot实现自动化配置核心注解

Spring 框架常见的注解

SpringMVC常见的注解有哪些?

Springboot常见的注解有哪些?

Mybatis执行流程

Mybatis是否支持延迟加载?

Mybatis的一级,二级缓存用过吗?

一级缓存:基于PrepetualCache的hashMap本地缓存,其存储域为Session,当Session进行flush或close后,该Sessio中所有Cache将清空,默认打开一级缓存

JVM篇

1 jvm是什么

Java virtual Machine java程序运行时环境(java二进制的运行时环境)

2 JVM由哪些部分组成,运行流程是什么

3  什么是程序计数器?

线程私有的,每个线程一份,内部保存的字节码的行号,用于记录正在执行的字节码指令地址

4 java堆

线程共享区域:主要用来保存对象实例,数组,当堆没有内存空间可分配给实例,也无法再扩展时,则抛出OutofMermoryError异常

组成:年轻代,老年代

        年轻代:Eden区 和两个幸存者区

        老年代;保存生命周期长的对象

5 什么是虚拟机栈

1 每个线程运行时所需要的内存,称为虚拟机栈

2 每个栈由多个栈帧组成,对应每次方法调用时所占内存 

3 每个线程只有一个活动栈帧,对应正在执行的哪个方法

6 垃圾回收是否涉及栈内存

垃圾回收主要指的是堆内存,当栈帧弹栈以后,内存就会释放

7 栈内存分配越大越好吗?

栈帧过大会导致线程数变少

8 方法的局部变量是否线程安全

如果方法内的局部变量没有逃离方法的作用范围,是线程安全的

如果局部变量引用了对象,并逃离方法的作用范围,需要考虑线程安全

9 什么情况下会导致栈内存溢出

栈帧过多会导致栈内存溢出

10 堆栈的区别是什么

栈内存一般会用来存储局部变量和方法调用,但堆内存是用来存储Java对象和数组的,堆会GC垃圾回收,而栈不会

栈内存是私有的,而堆内存是线程共享的

两者异常错误不同,但是如果栈内存或者堆内存不足,都会抛出异常

实战八股文

创新思路:

1 问设计模式有哪些?你最常用哪些?

在Java后端开发中,设计模式是一种重要的编程范式,用于解决常见的软件设计问题。以下是一些常见的设计模式:

1. 创建型模式:
   - 单例模式(Singleton Pattern):确保一个类只有一个实例。
   - 工厂模式(Factory Pattern):根据条件创建不同类型的对象。
   - 建造者模式(Builder Pattern):通过逐步构建复杂对象来创建对象。
   - 原型模式(Prototype Pattern):通过复制现有对象来创建新对象。

2. 结构型模式:
   - 适配器模式(Adapter Pattern):将一个类的接口转换为客户端所期望的另一种接口。
   - 装饰器模式(Decorator Pattern):动态地给对象添加额外的职责。
   - 代理模式(Proxy Pattern):控制对其他对象的访问。
   - 桥接模式(Bridge Pattern):把抽象和实现解耦,使它们可以独立变化。

3. 行为型模式:
   - 观察者模式(Observer Pattern):定义对象间的一种一对多的依赖关系。
   - 策略模式(Strategy Pattern):定义一系列算法,将每个算法封装起来,并使它们可以互换。
   - 命令模式(Command Pattern):将请求封装成对象,以便使用不同的请求、队列或日志来参数化其他对象。
   - 模板方法模式(Template Method Pattern):定义一个操作中的算法骨架,将一些步骤延迟到子类中实现。

对于我个人而言,在实际开发中,我最常用的设计模式是单例模式、工厂模式和观察者模式。这三种设计模式在很多场景下都能帮助解决常见的问题,提高代码的重用性和灵活性。但实际使用的设计模式还要根据具体的项目需求和场景进行选择。

2 谈谈对于线程的一些理解

线程是计算机中的一种基本的执行单位,它可以独立地运行,并且能够与其他线程共享内存空间。在Java中,线程是通过Thread类来实现的。

以下是我对线程的一些理解:

1. 线程的优点:线程可以提高程序的并发性,充分利用CPU资源,提高程序的响应速度和处理能力。通过线程,我们可以将耗时的操作放到后台进行,避免阻塞主线程。

2. 线程的状态:线程在运行过程中会有不同的状态,包括新建状态、就绪状态、运行状态、阻塞状态和死亡状态。不同的状态对应着线程生命周期中的不同阶段,也需要不同的操作来进行处理。

3. 线程的同步:线程之间的并发执行可能会出现一些问题,如竞态条件、死锁等。为了解决这些问题,我们需要使用同步机制,如synchronized关键字、Lock接口、Atomic变量等,来保证线程之间的协作和数据的一致性。

4. 线程的通信:线程之间需要相互通信,以实现协作完成任务。Java提供了多种方式来实现线程通信,如wait/notify机制、Condition接口、管道等。

5. 线程的创建:在Java中,我们可以通过继承Thread类或实现Runnable接口来创建线程。同时,使用线程池可以更好地管理和控制线程的数量和生命周期。

总之,线程是Java中非常重要的概念,了解线程的基本原理和使用方法对于编写高效、稳定的并发程序非常重要。

3 单点登录原理图

单点登录

4 查看linux内核版本该用哪些命令

uname -r 这个命令会显示当前正在运行的内核版本号

cat /proc/version 个命令会显示包括内核版本在内的系统版本信息。

cat /proc/sys/kernel/osrelease 这个命令会显示当前正在运行的内核版本号。

dmesg | grep "Linux version" 这个命令会显示内核启动时的信息,其中包括内核版本号。
 

4 ack怎么用

Awk是一种强大的文本处理工具,它可以用于对结构化文本文件进行处理和分析。下面是使用Awk的基本用法:

1. 执行Awk脚本:
   ```
   awk '脚本' 文件名
   ```

2. 打印文件的每一行:
   ```
   awk '{print}' 文件名
   ```

3. 根据字段进行操作:
   - 打印指定字段:使用$符号加上字段编号,从1开始计数。
     ```
     awk '{print $1, $2}' 文件名
     ```
   - 打印最后一个字段:
     ```
     awk '{print $NF}' 文件名
     ```

4. 使用条件进行筛选:
   ```
   awk '条件 {print}' 文件名
   ```

5. 使用分隔符进行字段划分:
   - 使用空格作为分隔符:
     ```
     awk -F" " '{print $1, $2}' 文件名
     ```
   - 使用逗号作为分隔符:
     ```
     awk -F"," '{print $1, $2}' 文件名
     ```

6. 自定义变量:
   ```
   awk 'BEGIN{变量=值} 条件 {print 变量}' 文件名
   ```

7. 使用Awk内置函数:
   - length:获取字符串长度。
   - substr:获取子串。
   - toupper:将字符串转换为大写。
   - tolower:将字符串转换为小写。

以上是Awk的基本用法,你可以根据具体需求使用更多的Awk特性和函数来进行文本处理和分析。

5 想要看进程树该怎么操作

要查看进程树结构,可以使用`pstree`命令。以下是一些常用的参数:

1. `-p`:显示进程ID。
2. `-u`:显示进程所属的用户名。
3. `-n`:以数字排序方式显示进程树。
4. `-a`:显示命令行参数。
5. `-h`:显示帮助信息。

例如,要显示进程树结构以及每个进程的PID和命令行参数,可以使用以下命令:
```
pstree -ap
```

这将以树状结构显示所有进程,并显示每个进程的PID和命令行参数。

注意:`pstree`命令在不同的Linux发行版中可能会有些许差异,你可以使用`man pstree`命令来查看特定发行版下的帮助文档,了解更多参数和用法。

6 问 spring中bean的作用域;

在Spring框架中,Bean的作用域指定了在应用程序中创建和管理Bean实例的方式。Spring提供了以下常见的Bean作用域:

1. Singleton(单例):默认的作用域,每个Spring容器中只有一个Bean实例。无论是通过依赖注入还是通过程序获取Bean,都将返回同一个实例。

2. Prototype(原型):每次请求Bean时,Spring容器都会创建一个新的Bean实例。每个获取Bean的地方都会得到不同的实例。

3. Request(请求):每个HTTP请求都会创建一个新的Bean实例,该Bean仅在当前HTTP请求内有效。在同一个请求中,多次获取该Bean将得到同一个实例。

4. Session(会话):每个用户会话(Session)都会创建一个新的Bean实例,该Bean仅在当前会话内有效。在同一个会话中,多次获取该Bean将得到同一个实例。

5. Global Session(全局会话):仅适用于基于Portlet的Web应用程序。每个全局会话都会创建一个新的Bean实例,该Bean仅在当前全局会话内有效。

6. Custom(自定义):可以通过实现`org.springframework.beans.factory.config.Scope`接口来定义自己的作用域。

通过在Spring配置文件或使用注解的方式,您可以为每个Bean定义所需的作用域。选择适当的作用域可以根据应用程序的需求,实现对Bean实例的合理管理和控制。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值