2021春招Java面试题大全(精华四)

返回首页

35.几种锁

乐观锁 VS 悲观锁

乐观锁:而乐观锁认为自己在使用数据时不会有别的线程修改数据,所以不会添加锁,只是在更新数据的时候去判断之前有没有别的线程更新了这个数据。如果这个数据没有被更新,当前线程将自己修改的数据成功写入。如果数据已经被其他线程更新,则根据不同的实现方式执行不同的操作(例如报错或者自动重试)。

悲观锁认为自己在使用数据的时候一定有别的线程来修改数据,因此在获取数据的时候会先加锁,确保数据不会被别的线程修改。Java中,synchronized关键字和Lock的实现类都是悲观锁。

公平锁和非公平锁

公平锁:是指多个线程按照申请锁的顺序来获取锁,类似排队打饭,先来后到

非公平锁:是指多个线程获取锁的 顺序并不是按照申请锁的顺序,有可能后申请的线程比先申请的线程优先获取锁。(插队)在高并发情况下,有可能造成优先级翻转或者饥饿现象(饥饿是指一直有人插队,然后最后的人一直获得不到锁 )。(先抢先得,抢不到再先来后到

ReentrantLock默认是非公平锁,Synchronized也是非公平锁,非公平锁的优点在于吞吐量大

可重入锁(递归锁)

可重入锁:线程可以进入任何一个它已经拥有的锁所同步的代码块。(可重入就是说某个线程已经获得某个锁,可以再次获取锁而不会出现死锁。)

在这里插入图片描述

比如我们进入到了method01获得了锁,那么我们也就可以直接获得method02的锁。

自旋锁

指尝试获得锁的线程不会立即阻塞,而是采用循环的方式去尝试获得锁。

好处是减少了线程上下文切换的消耗,缺点是循环会消耗CPU

读写锁

独占锁:指该锁一次只能被一个线程锁持有(ReentrantLock和Synchronized都是独占锁)

共享锁:该锁可以被多个线程锁持有

读写锁:多个线程同时读取一个共享资源没有任何问题,所以为了满足并发量,读取共享资源可以同时进行。但是,如果有一个线程想去写共享资源,就不能有其他线程来对资源进行读和写。

36.IoC控制反转

Spring的IoC:将创建并使用对象的过程由原来对象的执行者反向依托于Spring的过程了。Spring替我们创建对象,替我们保存对象,我们再需要用对象的时候去Spring中拿就行了。

Ioc就是Spring的一个容器,Ioc的加载过程依托于ApplicationContext(应用上下文)。它加载的时候是通过一系列继承,继承一个AbstractApplicationContext抽象类,这个抽象类里整合了两个资源,一个资源叫做ResourcePatternResolver,一个叫做ResourceLoader。ResourcePatternResolver用来解析文件内容(标签)(因为传来的文件可能是jar、xml等等,需要不同的方式打开这些资源。解析器就是负责把这些文件翻译成Spring能认识的东西),ResourceLoader用来加载配置文件(把资源读到Spring体系中)。(当我们创建ApplicationContext对象的时候,ApplicationContext对象会结合ResourcePatternResolver和ResourceLoader)他们会把所有配置在配置文件中的bean创建出来,放到beanFactory这个容器中。beanFactory中有beanBehaver,通过id找bean,通过type找bean。通过这些找bean的容器的对象,每个这样的对象都是ConcurrentHashMap。这就是IoC容器。调用对象其实调用的是AbstractApplicationContext的getBean方法,通过传进来的id或type到对应的容器去找对象。

37.FactoryBean和BeanFactory的区别

FactoryBean就是一个用户自定义创建对象的工具,它是Spring为了让其他的框架能融入到自己的体系中而开放的创建对象的接口,BeanFactory是容器,我们通过Spring管理的对象都放在这里面

38.DI(依赖注入)

IoC就是创建对象的过程,DI就是注入属性的过程

39.为什么mysql的默认隔离级别是REPEATABLE READ?

因为REPEATABLE READ可以解决不可重复读,脏读的问题,而幻读在业务中不是那么的重要,所以他就将隔离级别设置为REPEATABLE READ。Orcle隔离级别是RC,他是商业大型数据库,他要求效率高,所以隔离级别能低点,但是他不能解决不可重读的问题。
数据库的事务隔离越严格,并发副作用越小,但付出的代价也就越大,因为事务隔离实质上就是使事务在一定程度上 “串行化”进行,这显然与“并发”是矛盾的。应用可以根据自己的业务逻辑要求,通过选择不同的隔离级别来平衡 “隔离”与“并发”的矛盾。

40.什么是线程池?他的主要优势是什么

线程池做的工作主要是控制运行的线程的数量,处理过程中将任务放入队列,然后在线程创建后启动这些任务,如果请求数量超过了线程最大数量,则超出数量的请求排队等候,等其他线程执行完毕,再从队列中取出任务来执行。

他的主要特点是:线程复用;控制最大并发数;管理线程。

第一:降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。

第二:提高响应速度。当任务到达时,任务可以不需要等待线程创建,直接就能执行。

第三:提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。

41.线程池3个常用方式

线程池的底层就是返回ThreadPoolExecutor这个类

三个创建方式

  • newFixedThreadPool(int):一池固定数线程
    • 适用场景:执行长期的任务,性能好很多
    • newFixedThreadPool创建的线程池corePoolSize和maximumPoolSize值是相等的,它使用的是LinkedBlockingQueue
  • newSingleThreadExecutor():一池一线程
    • 一个任务一个任务执行的场景
    • 将上面两个参数设置为1,也使用的是LinkedBlockingQueue
  • newCachedThreadPool():一池多线程
    • 执行很多短期异步的小程序或者负载较轻的服务器
    • 他创建的线程池corePoolSize值为0,maximumPoolSize值为Integer的最大值,使用的是SynchronousQueue,也就是说来了任务就创建线程运行,当线程空闲超过60秒,就会销毁线程。
ExecutorService service = Executors.newFixedThreadPool(5);//一池5个处理线程。ExecutorService相当于一个银行,参数5表示有5个办理窗口
        ExecutorService service1 = Executors.newSingleThreadExecutor();//一池一个处理线程
        ExecutorService service2 = Executors.newCachedThreadPool();//一池n线程

        try {
            //模拟10个用户来办理业务,每个用户就是一个来自外部的请求线程。
            for (int i = 1; i <= 10; i++) {
                service2.execute(new Runnable() {
                    @Override
                    public void run() {
                        System.out.println(Thread.currentThread().getName()+"啦啦啦");
                    }
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            service2.shutdown();
        }

42.线程池七大参数

  • corePoolSize:线程池中的常驻核心线程数(初始化的线程数)
    • 创建了线程池后,当有请求任务来之后,就会安排池中的线程去执行请求任务(近似理解为今日当值窗口)。
    • 当线程池中的线程数目达到corePoolSize后,就会把到达的任务放到缓存队列当中。
  • maximumPoolSize:线程池能够容纳同时执行的最大线程数,此值必须大于等于1
  • keepAliveTime:多余的空闲线程的存活时间。
    • 当前线程池数量超过corePoolSize时,当空闲时间达到keepAliveTime值时,多余空闲线程或被销毁直到只剩下corePoolSize个线程为止
    • 随着业务量的下降,在规定的时间内,没有多余的请求了,那么多余的空闲线程会被销毁,直到只剩下corePoolSize个线程
  • unit:keepAliveTime的单位
  • workQueue:任务队列,被提交但尚未被执行的任务
  • handler:拒绝策略,表示当等待队列满了并且工作线程数达到线程池最大线程数(maximumPoolSize)时如何来拒绝业务请求的策略
  • threadFactory:表示生成线程池中工作线程的线程工厂,用于创建线程,一般用默认的就可以了。

43.线程池底层工作原理

  1. 在创建了线程池以后,等待提交过来的任务请求。

  2. 当调用execute()方法添加一个请求任务时,线程池会做如下判断:

    2.1 如果正在运行的线程数量小于corePoolSize,那么马上创建线程运行这个任务;

    2.2 如果正在运行的线程数量大于或等于corePoolSize,那么将这个任务放入等待队列

    2.3 如果这时候等待队列满了且正在运行的线程数量还小于maximumPoolSize,那么还是要创建非核心线程立刻运行这个任务。

    2.4 如果队列满了且真正运行的线程数量大于或等于maximumPoolSize,那么线程池会启动拒绝策略。

  3. 当一个线程完成任务时,他会从等待队列中取下一个任务来执行。

  4. 当一个线程无事可做超过一定时间(keepAliveTime)时,线程池会判断:

    如果当前的线程数大于corePoolSize,那么这个多余空闲的线程就被销毁。

    所以线程池的所有任务完成后他最终会收缩到corePoolSize的大小。

44.线程池的四种拒绝策略

拒绝策略指的就是:等待队列已经排满了,同时线程池中的线程数也达到了最大值,无法为新任务服务时,这时就需要启动拒绝策略

JDK内置的拒绝策略:

  • AbortPolicy(默认):直接抛出RejectExecutionException异常阻止系统正常运行
  • CallerRunsPolicy:不会抛弃任务也不会抛出异常,而是将某些任务回退到调用者
  • DiscardOldestPolicy:抛弃队列中等待最久的任务,然后把当前任务加入队列中尝试再次提交当前任务
  • DiscardPolicy:直接丢弃任务,不做任何处理也不会抛出异常

45.类和实例初始化顺序

(1) 父类静态代码块(包括静态初始化块,静态属性,但不包括静态方法)

(2) 子类静态代码块(包括静态初始化块,静态属性,但不包括静态方法 )

(3) 父类非静态代码块普通成员变量( 包括非静态初始化块,非静态属性 )

(4) 父类构造函数

(5) 子类非静态代码块普通成员变量( 包括非静态初始化块,非静态属性 )

(6) 子类构造函数

其中:类中静态块按照声明顺序执行,并且(1)和(2)不需要调用new类实例的时候就执行了(意思就是在类加载到方法区的时候执行的)

别忘了main方法也是静态方法哦!!!

别忘了子类会重写父类的方法哦!!!

重写要注意:

final方法,静态方法,private修饰的方法不能被重写。

子类的返回值类型要小于等于父类方法返回类型

子类抛出的异常要小于等于父类方法抛出的异常

子类访问权限要大于等于父类方法访问权限

46. 方法的参数传递机制

形参是基本数据类型,传指(不会改变原值)

形参是引用数据类型,传地址(会改变原值)

注意:特殊类型:String、包装类等对象的不可变性

47.局部变量与成员变量

  • 局部变量:声明在方法体、代码块、形参中

  • 成员变量在类中方法外:分为类变量(有static)和实例变量(没有static)

  • 局部变量只能被final修饰,不能被访问修饰符、static、volatile等修饰

  • 局部变量存储在栈中、实例变量存在堆中、类变量存储在方法区中

48.Spring中Bean的作用域

  • Singleton:默认值。当IOC一创建就会创建Bean的实例,而且是单例的
  • prototype:原型的。当IOC容器一创建不在实例化Bean对象,而是在getBean()时再实例化该bean
  • request:每次请求实例化一个bean
  • session:再一次会话中共享一个bean

49.在SpringMVC中解决Post请求中文乱码问题

解决Post请求中文乱码问题,在web.xml中配置过滤器(设置encoding解决请求乱码,设置forceEncoding为true解决响应乱码)

SpringMVC提供了一个过滤器:CharacterEncodingFilter,它里面有一个doFilterInternal方法

50.什么是索引,以及索引的优缺点?

索引是一种数据结构,可以帮助我们快速的进行排好序的数据的查找。

索引是存放在磁盘上的。我们从磁盘上寻找数据的过程是:磁盘先旋转,然后磁头在移动。这就是一次取数据的过程,叫做一次IO。

所以如果我们没有加索引,就需要进行全表查询,那么我们在查找一张表的一行数据就要进行一次IO。太太太费时了!所以加了索引就可以提高我们的查找效率。


磁盘的存储原理:(我们的数据存储在磁盘上的不同位置上)

寻道时间(速度慢,耗时)+旋转时间(较快)

(磁盘是顺时针或者逆时针旋转,磁头是左右移动)

索引的数据结构和具体存储引擎的实现有关。在MySQL中使用较多的索引有Hash索引,B+树索引等。

我们经常使用的 InnoDB存储引擎的默认索引实现为:B+树索引。 默认使用的是可重复读隔离级别.

优点:检索查询速度快,排序快

缺点:创建索引和维护索引要耗费时间,具体地,当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,会降低增/改/删的执行效率;索引需要占物理空间。


为啥索引的底层数据结构不用二叉树,或者红黑树,而要用B+树呢???

  • 如果我们的索引建立的不规范,我们很容易使二叉树变为瘸子(插入123456,所有节点都是右节点),这跟全表查询没啥区别。

  • 我们红黑树的高度计算是h = log2^n,如果有100万条数据,这个树的高度还是相当高的。所以IO次数还是挺多的。

  • 如果我们可以让每个结点存储更多的索引值,我们一次IO就可以查询这个多的索引值,然后放到内存中,然后我们在内存中具体查找,在内存中查找的速度可以是忽略不计的。这就是B树的存储原理。

51.索引使用场景

where:通过某个建立了索引的字段查询记录,效率会很高

order by:将查询结果按照某个字段排序时,如果该字段没有建立索引,需要将查询涉及到的所有数据从磁盘中读到内存,然后再排序,很影响性能。而索引天生是有序的。

join:对join语句匹配关系(on)涉及的字段建立索引能够提高效率

覆盖索引:如果要查询的字段都建立过索引,那么引擎会直接在索引表中查询而回表查询(否则只要有一个字段没有建立索引就会做全表扫描),这叫索引覆盖。因此我们需要尽可能的在select后只写必要的查询字段,以增加索引覆盖的几率。

覆盖索引:索引的数据覆盖了需要查询的所有数据

52.索引有哪几种类型?

  • 主键索引: 数据列不允许重复,不允许为NULL,一个表只能有一个主键。
  • 唯一索引: 数据列不允许重复,允许为NULL值,一个表允许多个列创建唯一索引。
    • 可以通过 ALTER TABLE table_name ADD UNIQUE (column); 创建唯一索引
  • 普通索引: 基本的索引类型,没有唯一性的限制,允许为NULL值。
    • 可以通过ALTER TABLE table_name ADD INDEX index_name (column);创建普通索引
  • 全文索引: 是目前搜索引擎使用的一种关键技术。
    • 可以通过ALTER TABLE table_name ADD FULLTEXT (column);创建全文索引
什么是聚簇索引?什么是回表查询?

聚簇索引是索引的一种实现方案

  • InnoDB聚簇索引:叶子节点存储数据行。将数据存储与索引放到了一块,找到索引也就找到了数据行

  • 非聚簇索引:叶子节点存储主键值。先通过索引找到主键值,然后在找到对应的数据行。(需要扫码两遍索引树)

回表查询 ,先定位主键值,再定位行记录

53.创建索引的原则

需要创建索引的情况

  • 频繁作为查询条件的字段应该创建索引

  • 查询中统计或者分组的字段

  • 查询中排序的字段

  • 外键要建立索引

不需要创建索引的情况

  • 表记录太少
  • 经常增删改的表或字段
  • where条件里用不到的字段不创建索引
  • 过滤性不好的不适合创建索引

54.索引的数据结构,Hash索引和B+树索引的区别

Hash索引和B+树索引的底层实现原理:

hash索引底层就是hash表,进行查找时,调用一次hash函数就可以获取到相应的键值,之后进行回表查询获得实际数据.B+树底层实现是多路平衡查找树.对于每一次的查询都是从根节点出发,查找到叶子节点方可以获得所查键值,然后根据查询判断是否需要回表查询数据.

他们之间的不同点:

  • hash索引进行等值查询更快(一般情况下),但是却无法进行范围查询。B+树天然支持范围查询
  • hash索引不支持模糊查询以及多列索引的最左前缀匹配.原理也是因为hash函数的不可预测
  • hash索引任何时候都避免不了回表查询数据,而B+树在符合某些条件(聚簇索引,覆盖索引等)的时候可以只通过索引完成查询.
  • hash索引虽然在等值查询上较快,但是不稳定.性能不可预测,当某个键值存在大量重复的时候,发生hash碰撞,此时效率可能极差.而B+树的查询效率比较稳定,对于所有的查询都是从根节点到叶子节点,且树的高度较低。

55.什么是聚簇索引?

在B+树的索引中,叶子节点可能存储了当前的key值,也可能存储了当前的key值以及整行的数据,这就是聚簇索引和非聚簇索引.

在InnoDB中,只有主键索引是聚簇索引,如果没有主键,则挑选一个唯一键建立聚簇索引.如果没有唯一键,则隐式的生成一个键来建立聚簇索引。

当查询使用聚簇索引时,在对应的叶子节点,可以获取到整行数据,因此不用再次进行回表查询。

56.在建立索引的时候,都有哪些需要考虑的因素呢?

建立索引的时候一般要考虑字段的使用频率,经常作为条件进行查询的字段比较适合。如果需要建立联合索引还需要考虑联合索引的命中顺序。一般情况下,将查询需求频繁或者字段选择性高的列放在前面。

创建的索引有没有被使用到?或者说怎么才可以知道这条语句运行很慢的原因?

MySQL提供了explain命令来查看语句的执行计划

57.联合索引是什么?什么是最左匹配原则

联合索引:在检索数据时从联合索引的最左边开始匹配。

比如我们建立了一个联合索引(id,name,age),实际上相当于建立了三个索引(id)(id,name)(id,name,age)

我们在进行全值匹配查询时,只有符合上面那三个顺序的查询才会命中索引,但是会发现不论是使用(id,age,name)(name,id,age)还是(age,name,id)顺序,在查询时都使用到了联合索引, 这是因为MySQL中有查询优化器explain

58.什么情况下MySQL无法使用索引?

  • 使用不等于查询
  • 列参与了数学运算或者函数
  • 在字符串like时左边是通配符.类似于’%aaa’.
  • 当mysql分析全表扫描比使用索引快的时候不使用索引.
  • 当使用联合索引,前面一个条件为范围查询,后面的即使符合最左前缀原则,也无法使用索引.

59.什么是数据库事务?

数据库的事务是指一组sql语句组成的数据库逻辑处理单元,在这组的sql操作中,要么全部执行成功,要么全部执行失败。

60.ACID

原子性:事务是一组不可分割的操作单元,这组单元要么同时成功要么同时失败(由DBMS的事务管理子系统来实现);
一致性:事务前后的数据完整性要保持一致(由DBMS的完整性子系统执行测试任务);
隔离性:多个用户的事务之间不要相互影响,要相互隔离(由DBMS的并发控制子系统实现);
持久性:一个事务一旦提交,那么它对数据库产生的影响就是永久的不可逆的,如果后面再回滚或者出异常,都不会影响已提交的事务(由DBMS的恢复管理子系统实现的)

ACID靠什么保证的呢?

A原子性由undo log日志保证,它记录了需要回滚的日志信息,事务回滚时撤销已经执行成功的sql

C一致性一般由代码层面来保证

I隔离性由MVCC来保证

D持久性由内存+redo log来保证,mysql修改数据同时在内存和redo log记录这次操作,事务提交的时候通过redo log刷盘,宕机的时候可以从redo log恢复

61. 为什么InnoDB表要尽量设定一个主键,并且推荐使用整型自增的?

主键是数据库确保数据行在整张表唯一性的保障,即使业务上本张表没有主键,也建议添加一个自增长的ID列作为主键。如果我们没有建立索引,Mysql也会在后台建立一个默认的主键索引。

设定了主键之后,在后续的删改查的时候可能更加快速以及确保操作数据范围安全.

62.字段为什么要求定义为not null?

null值会占用更多的字节,且会在程序中造成很多与预期不符的情况.

63.MySQL支持哪些存储引擎?

MySQL支持多种存储引擎,比如InnoDB,MyISAM等等.

InnoDB也是MySQL的默认存储引擎.

存储引擎是针对表来说的我们不同的表可以选择不同的存储引擎

64. InnoDB和MyISAM有什么区别?

  • InnoDB支持事物,而MyISAM不支持事物
  • InnoDB支持行级锁,表级锁定,锁定力度小并发能力高,而MyISAM支持表级锁
  • InnoDB支持MVCC, 而MyISAM不支持
  • InnoDB支持外键,而MyISAM不支持
  • InnoDB不支持全文索引,而MyISAM支持。
  • InnoDB进行INSERT、UPDATE、DELETE更优,MyISAM进行SELECT更优。
  • InnoDB的主键索引是聚簇索引,叶子节点存储着行数据,MyISAM索引是非聚簇索引,叶子节点存储的是行数据地址,需要再寻址一次才能得到数据。

65. MySQL中的varchar和char有什么区别

char是定长的,申请多长就占用多长,而varchar是变长的,也就是说申请的只是最大长度,占用的空间为实际字符长度+1,最后一个字符存储使用了多长的空间.

在检索效率上来讲,char > varchar

因此在使用中,如果确定某个字段的值的长度,可以使用char,否则应该尽量使用varchar.例如存储用户MD5加密后的密码,则应该使用char.

varchar(10)和int(10)代表什么含义?

varchar的10代表了申请的空间长度,也是可以存储的数据的最大长度,而int的10只是代表了展示的长度,不足10位以0填充.

也就是说,int(1)和int(10)所能存储的数字大小以及占用的空间都是相同的,只是在展示时按照长度展示。

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C语言面试八股文是指在春季招聘中常见的C语言相关的面试题目和知识点。下面是一份常见的C语言面试八股文,供您参考: 1. C语言的基本数据类型有哪些? C语言的基本数据类型包括整型、浮点型、字符型和指针型。 2. 请介绍一下C语言中的变量和常量。 变量是用来存储数据的内存位置,可以通过变量名来访问和修改其值。常量是指在程序执行过程中不会改变的值。 3. 什么是数组?请介绍一下C语言中的数组。 数组是一种存储相同类型数据的集合,通过索引来访问数组中的元素。在C语言中,数组的大小在定义时就需要确定,并且数组的下标从0开始。 4. 请介绍一下C语言中的指针。 指针是一个变量,其值为另一个变量的地址。通过指针可以直接访问和修改内存中的数据。使用指针可以提高程序的效率和灵活性。 5. 请介绍一下C语言中的函数。 函数是一段完成特定任务的代码块,可以通过函数名来调用执行。函数可以接收参数并返回一个值,也可以不接收参数或不返回值。 6. 请介绍一下C语言中的流程控制语句。 C语言中的流程控制语句包括条件语句(if-else语句、switch语句)、循环语句(for循环、while循环、do-while循环)和跳转语句(break语句、continue语句、goto语句)。 7. 请介绍一下C语言中的结构体。 结构体是一种自定义的数据类型,可以包含多个不同类型的成员变量。通过结构体可以将多个相关的数据组织在一起。 8. 请介绍一下C语言中的文件操作。 C语言中的文件操作主要包括打开文件、读写文件和关闭文件。可以使用标准库函数来进行文件操作,如fopen、fread、fwrite、fclose等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值