论码农的自我修养:并发,数据库,Spring面试开发三件套

并发编程、数据库和Spring,我认为这个算程序员开发面试的三件套吧。Spring提供开发,数据库是使用数据的维护和获取,并发是为了提升程序的性能,还都是挺重要的,都是离不开的。天天看一看,开发不困难。
在这里插入图片描述java

1、并发编程

另外本人整理了20年面试题大全,包含spring、并发、数据库、Redis、分布式、dubbo、JVM、微服务等方面总结,下图是部分截图,须要的话点这里点这里,暗号CSDN。mysql

在这里插入图片描述
一、Java 中实现多线程有几种方法程序员

(1)继承 Thread 类;web

(2)实现 Runnable 接口;面试

(3)实现 Callable 接口经过 FutureTask 包装器来建立 Thread 线程;正则表达式

(4)使用 ExecutorService、Callable、Future 实现有返回结果的多线程(也就是使用了 ExecutorService 来管理前面的三种方式)。spring

二、如何中止一个正在运行的线程sql

(1)使用退出标志,使线程正常退出,也就是当 run 方法完成后线程终止。数据库

(2)使用 stop 方法强行终止,可是不推荐这个方法,由于 stop 和 suspend 及 resume 同样都是过时做废的方法。编程

(3)使用 interrupt 方法中断线程。

class MyThread extends Thread { 
 
  
    volatile Boolean stop = false;
    public void run() { 
 
  
        while (!stop) { 
 
  
            System.out.println(getName() + " is running");
            try { 
 
  
                sleep(1000);
            }
            catch (InterruptedException e) { 
 
  
                System.out.println("week up from blcok...");
                stop = true;
                // 在异常处理代码中修改共享变量的状态
            }
        }
        System.out.println(getName() + " is exiting...");
    }
}
class InterruptThreadDemo3 { 
 
  
    public static void main(String[] args) throws InterruptedException { 
 
  
        MyThread m1 = new MyThread();
        System.out.println("Starting thread...");
        m1.start();
        Thread.sleep(3000);
        m1.interrupt();
        // 阻塞时退出阻塞状态
        Thread.sleep(3000);
        // 主线程休眠 3 秒以便观察线程 m1 的中断状况
        System.out.println("Stopping application...");
    }
}

三、notify()和 notifyAll()有什么区别?

notify 可能会致使死锁,而 notifyAll 则不会

任什么时候候只有一个线程能够得到锁,也就是说只有一个线程能够运行 synchronized 中的代码使用 notifyall,能够唤醒全部处于 wait 状态的线程,使其从新进入锁的争夺队列中,而 notify 只能唤醒一个。

wait() 应配合 while 循环使用,不该使用 if,务必在 wait()调用先后都检查条件,若是不知足,必须调用 notify()唤醒另外的线程来处理,本身继续 wait()直至条件知足再往下执行。

notify() 是对 notifyAll()的一个优化,但它有很精确的应用场景,而且要求正确使用。否则可能致使死锁。正确的场景应该是 WaitSet 中等待的是相同的条件,唤醒任一个都能正确处理接下来的事项,若是唤醒的线程没法正确处理,务必确保继续 notify()下一个线程,而且自身须要从新回到 WaitSet 中。

四、sleep()和 wait() 有什么区别?

对于 sleep()方法,咱们首先要知道该方法是属于 Thread 类中的。而 wait()方法,则是属于 Object 类中
的。

sleep()方法致使了程序暂停执行指定的时间,让出 cpu 该其余线程,可是他的监控状态依然保持者,当指定的时间到了又会自动恢复运行状态。在调用 sleep()方法的过程当中,线程不会释放对象锁。

当调用 wait()方法的时候,线程会放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象调用 notify()方法后本线程才进入对象锁定池准备,获取对象锁进入运行状态。

五、volatile 是什么?能够保证有序性吗?

一旦一个共享变量(类的成员变量、类的静态成员变量)被 volatile 修饰以后,那么就具有了两层语义:

(1)保证了不一样线程对这个变量进行操做时的可见性,即一个线程修改了某个变量的值,这新值对其余线程来讲是当即可见的,volatile 关键字会强制将修改的值当即写入主存。

(2)禁止进行指令重排序。

volatile 不是原子性操做

什么叫保证部分有序性?

当程序执行到 volatile 变量的读操做或者写操做时,在其前面的操做的更改确定所有已经进行,且结果已经对后面的操做可见;在其后面的操做确定尚未进行;

x = 2;//语句 1
y = 0;//语句 2
flag = true;//语句 3
x = 4;//语句 4
y = -1;//语句 5

因为flag 变量为 volatile 变量,那么在进行指令重排序的过程的时候,不会将语句 3 放到语句 一、语句 2 前面,也不会讲语句 3 放到语句 四、语句 5 后面。可是要注意语句 1 和语句 2 的顺序、语句 4 和语句 5 的顺序是不做任何保证的。

使用 Volatile 通常用于 状态标记量 和 单例模式的双检锁

六、Thread 类中的 start() 和 run() 方法有什么区别?

start()方法被用来启动新建立的线程,并且 start()内部调用了 run()方法,这和直接调用 run()方法的效果不同。当你调用 run()方法的时候,只会是在原来的线程中调用,没有新的线程启动,start()方法才会启动新线程。

七、为何 wait, notify 和 notifyAll 这些方法不在 thread 类里面?

明显的缘由是 JAVA 提供的锁是对象级的而不是线程级的,每一个对象都有锁,经过线程得到。若是线程须要等待某些锁那么调用对象中的 wait()方法就有意义了。若是 wait()方法定义在 Thread 类中,线程正在等待的是哪一个锁就不明显了。简单的说,因为 wait,notify 和 notifyAll 都是锁级别的操做,因此把他们定义在 Object 类中由于锁属于对象。

八、为何 wait 和 notify 方法要在同步块中调用?

(1)只有在调用线程拥有某个对象的独占锁时,才可以调用该对象的 wait(),notify()和 notifyAll()方法。

(2)若是你不这么作,你的代码会抛出 IllegalMonitorStateException 异常。

(3)还有一个缘由是为了不 wait 和 notify 之间产生竞态条件。

wait()方法强制当前线程释放对象锁。这意味着在调用某对象的 wait()方法以前,当前线程必须已经得到该对象的锁。所以,线程必须在某个对象的同步方法或同步代码块中才能调用该对象的 wait()方法。

在调用对象的 notify()和 notifyAll()方法以前,调用线程必须已经获得该对象的锁。所以,必须在某个对象的同步方法或同步代码块中才能调用该对象的 notify()或 notifyAll()方法。

调用 wait()方法的缘由一般是,调用线程但愿某个特殊的状态(或变量)被设置以后再继续执行。调用 notify()或 notifyAll()方法的缘由一般是,调用线程但愿告诉其余等待中的线程:“特殊状态已经被设置”。这个状态做为线程间通讯的通道,它必须是一个可变的共享状态(或变量)。

九、Java 中 interrupted 和 isInterruptedd 方法的区别?

interrupted() 和 isInterrupted()的主要区别是前者会将中断状态清除然后者不会。Java 多线程的中断机制是用内部标识来实现的,调用 Thread.interrupt()来中断一个线程就会设置中断标识为 true。当中断线程调用静态方法 Thread.interrupted()来检查中断状态时,中断状态会被清零。而非静态方法 isInterrupted()用来查询其它线程的中断状态且不会改变中断状态标识。简单的说就是任何抛出 InterruptedException 异常的方法都会将中断状态清零。不管如何,一个线程的中断状态有有可能被其它线程调用中断来改变。

十、Java 中 synchronized 和 ReentrantLock 有什么不一样?
类似点:

这两种同步方式有不少类似之处,它们都是加锁方式同步,并且都是阻塞式的同步,也就是说当若是一个线程得到了对象锁,进入了同步块,其余访问该同步块的线程都必须阻塞在同步块外面等待,而进行线程阻塞和唤醒的代价是比较高的。

区别:

这两种方式最大区别就是对于 Synchronized 来讲,它是 java 语言的关键字,是原生语法层面的互斥,须要 jvm 实现。而 ReentrantLock 它是 JDK 1.5 以后提供的 API 层面的互斥锁,须要 lock()和 unlock()方法配合 try/finally 语句块来完成。

Synchronized 进过编译,会在同步块的先后分别造成 monitorenter 和 monitorexit 这个两个字节码指令。在执行 monitorenter 指令时,首先要尝试获取对象锁。若是这个对象没被锁定,或者当前线程已经拥有了那个对象锁,把锁的计算器加 1,相应的,在执行 monitorexit 指令时会将锁计算器就减 1,当计算器为 0 时,锁就被释放了。若是获取对象锁失败,那当前线程就要阻塞,直到对象锁被另外一个线程释放为止。

因为 ReentrantLock 是 java.util.concurrent 包下提供的一套互斥锁,相比 Synchronized,ReentrantLock 类提供了一些高级功能,主要有如下 3 项:

(1)等待可中断,持有锁的线程长期不释放的时候,正在等待的线程能够选择放弃等待,这至关于 Synchronized 来讲能够避免出现死锁的状况。

(2)公平锁,多个线程等待同一个锁时,必须按照申请锁的时间顺序得到锁,Synchronized 锁非公平锁,ReentrantLock 默认的构造函数是建立的非公平锁,能够经过参数 true 设为公平锁,但公平锁表现的性能不是很好。

(3)锁绑定多个条件,一个 ReentrantLock 对象能够同时绑定对个对象。

2、MySQL

在这里插入图片描述

1.Mysql 中有哪几种锁?

(1)表级锁:开销小,加锁快。不会出现死锁,锁定粒度大,发生锁冲突的几率高,并发度低。

(2)行级锁:开销大,加锁慢。会出现死锁,锁定粒度小,发生锁冲突的几率低,并发度高。

(3)页面锁:开销时间、加锁时间、锁定粒度在 表级锁 与 行级锁 之间,会出现死锁,并发度中等。

2.CHAR 与 VARCHAR 的区别?

(1)CHAR 长度不可变,范围 1~255。若存储长度未达到定义的长度,则以 空格 填充。存取速度快,但容易浪费空间。

(2)VARCHAR 长度可变,范围 1~65535。若存储长度未达到定义的长度,则存实际长度数据。存取速度稍慢,但节约空间。

3.能说下myisam 和 innodb的区别吗?

myisam引擎是5.1版本以前的默认引擎,支持全文检索、压缩、空间函数等,可是不支持事务和行级锁,因此通常用于有大量查询少许插入的场景来使用,并且myisam不支持外键,而且索引和数据是分开存储的。

innodb是基于聚簇索引创建的,和myisam相反它支持事务、外键,而且经过MVCC来支持高并发,索引和数据存储在一块儿。

4.你能说下事务的基本特性和隔离级别吗?
事务:数据库中,对数据的一系列操做能够当作一个总体,称为事务。这个总体要么所有执行、要么所有不执行。
ACID 属性的存在确保了 事务的可靠。
(1)Actomicity(原子性):原子性要求 事务中的操做要么所有完成,要么回退成以前未操做的状态。即事务中某个操做失败后,会至关于什么都没发生,不会出现改了部分数据的状况。

(2)Consistency(一致性):一致性要求 事务执行先后,数据库的状态一致,即从一个一致性状态切换到另外一个一致性的状态。

(3)Isolation(隔离性):隔离性要求 并发的事务相互隔离、不可见。即一个事务看不见另外一个事务内部的操做以及操做的数据。

(4)Durability(持久性):持久性要求 事务对数据库数据的修改是永久的。即数据一旦修改提交后,其状态将永久不变。

5.并发问题 – 脏读、不可重复读、幻读?

对于同时运行的多个事务,若这些事务访问同一数据时,没有采用必要的隔离机制,则会形成以下的并发问题。
(1)脏读:脏读 指的是当一个事务正在访问某数据,并对这个数据进行的修改,且这条数据还未提交到数据库中,此时若另外一个事务也访问到这条数据,获取到的是这条被修改的数据,此时获得的数据不对,即脏读。
好比:tom 年龄为 22,事务 A 修改 tom 年龄为 30,此时还未提交到数据库,此时事务 B 获取 tom 年龄,获得的是 30,事务 A 回滚数据,数据库的数据依旧是 22,但事务 B 拿到的数据是 30,这就是脏读,读错了数据。

(2)不可重复读:指一个事务,屡次读取同一条数据,在这个事务还未结束时,另外一个事务也访问该数据并对其修改,那么可能形成事务屡次读取的数据不一致,即不可重复读。
好比:tom 年龄为 22,事务 A 读取 tom 年龄为 22,事务未结束。此时事务 B 修改 tom 年龄为 30,并提交到数据库,当事务 A 再次读取 tom 年龄为 30,事务 A 两次读取的数据不一致,即不可重复读。

(3)幻读:指事务并非独立执行时产生的现象。一个事务修改某个表,涉及表的全部行,同时另外一个事务也修改表,好比增长或删除一条数据。此时第一个事务发现多出或者少了一条数据。这种状况就是幻读。
好比:事务 A 查询当前表的数据总数为 11, 此时事务 B 向表中插入一条数据,事务 A 再次查询当前表数据总数为 12,即幻读。

注:
    不可重复读、幻读理解起来有些相似。
    不可重复读是对一条数据操做,重点在于修改某条数据。
    幻读是对表进行操做,重点在于新增或删除某条数据。

6.事务的隔离级别?

数据库系统必须具备隔离并发运行的事务的能力,使各事务间不会相互影响,避免并发问题。
  隔离级别:指的是一个事务与其余事务的隔离程度。隔离级别越高,则并发能力越弱。
(1)Read Uncommitted(读未提交):即读取到 未提交的内容。
  通常不使用。此隔离级别下,查询不会加锁,便可能存在两个事务操做同一个表的状况。可能会致使 “脏读”、“不可重复读”、“幻读”。

(2)Read Committed(读提交):即只能读取到 已提交的内容。
  经常使用(oracle、SQL Server 默认隔离级别)。此隔离级别下,查询采用 快照读 的机制,即不会读取到未提交的数据,从而避免 “脏读”,可是仍可能致使 “不可重复读”、“幻读”。

(3)Repeatable Read(可重复读)
  经常使用(mysql 默认隔离级别)。此隔离级别下,查询采用 快照读 的机制,且事务启动后,当前数据不能被修改,从而能够避免 “不可重复读”,可是仍可能致使 “幻读”(新增或删除某条数据)。

(4)Serializable(串行化)
  通常不使用。此隔离级别下,事务会串行化执行(排队执行),执行效率差、开销大。能够避免 “脏读”、“不可重复读”、“幻读“。

【举例:】
select @@transaction_isolation; -- 用于查看当前数据库的隔离级别(8.0版本)
 set session transaction isolation level read committed; --用于设置隔离级别为 read committed

7.说说自增主键、UUID?

(1)自增主键,数据在物理结构上是顺序存储,性能好,占用空间小。能够是 int 和 bigint 类型。int 4字节,bigint 8 字节,项目中理论不该出现 自增主键达到最大值的状况,由于数据太大,效率会大大下降,当出现必定的数据量后,应进行分库分表操做。

(2)UUID,数据在物理结构上是随机存储,性能较差,占用空间大。惟一ID,毫不冲突。

3、Spring

在这里插入图片描述

1. 什么是 Spring IOC 容器?

Spring 框架的核心是 Spring 容器。容器建立对象,将它们装配在一块儿,配置它们并管理它们的完整生命周期。Spring 容器使用依赖注入来管理组成应用程序的组件。容器经过读取提供的配置元数据来接收对象进行实例化,配置和组装的指令。该元数据能够经过 XML,Java 注解或 Java 代码提供。
在这里插入图片描述
2. 什么是依赖注入?

在依赖注入中,您没必要建立对象,但必须描述如何建立它们。您不是直接在代码中将组件和服务链接在一块儿,而是描述配置文件中哪些组件须要哪些服务。由 IoC 容器将它们装配在一块儿。

3. 能够经过多少种方式完成依赖注入?

一般,依赖注入能够经过三种方式完成,即:

构造函数注入
setter 注入
接口注入
在 Spring Framework 中,仅使用构造函数和 setter 注入。

4. 区分构造函数注入和 setter 注入。
在这里插入图片描述
5. spring 中有多少种 IOC 容器?

BeanFactory - BeanFactory 就像一个包含 bean 集合的工厂类。它会在客户端要求时实例化 bean。

ApplicationContext - ApplicationContext 接口扩展了 BeanFactory 接口。它在 BeanFactory 基础上提供了一些额外的功能。

6. 区分 BeanFactory 和 ApplicationContext。
在这里插入图片描述

8. 什么是 spring bean?

它们是构成用户应用程序主干的对象。
Bean 由 Spring IoC 容器管理。
它们由 Spring IoC 容器实例化,配置,装配和管理。
Bean 是基于用户提供给容器的配置元数据建立。
9. spring 提供了哪些配置方式?

基于 xml 配置

bean 所需的依赖项和服务在 XML 格式的配置文件中指定。这些配置文件一般包含许多 bean 定义和特定于应用程序的配置选项。它们一般以 bean 标签开头。例如:

<bean id="studentbean" class="org.edureka.firstSpring.StudentBean">
        <property name="name" value="Edureka"></property>
    </bean>

基于注解配置

您能够经过在相关的类,方法或字段声明上使用注解,将 bean 配置为组件类自己,而不是使用 XML 来描述 bean 装配。默认状况下,Spring 容器中未打开注解装配。所以,您须要在使用它以前在 Spring 配置文件中启用它。例如:

<beans>
        <context:annotation-config/>
        <!-- bean definitions go here -->
    </beans>

基于 Java API 配置

Spring 的 Java 配置是经过使用@Bean 和 @Configuration 来实现。

2.1.@Bean 注解扮演与 元素相同的角色。

2.2. @Configuration 类容许经过简单地调用同一个类中的其余@Bean 方法来定义 bean 间依赖关系。

例如:

public class StudentConfig { 
 
  
    @Bean
    public StudentBean myStudent() { 
 
  
        return new StudentBean();
    }
}

10.什么是 AOP?

AOP(Aspect-Oriented Programming), 即 面向切面编程, 它与 OOP( Object-Oriented Programming, 面向对象编程) 相辅相成, 提供了与 OOP 不一样的抽象软件结构的视角. 在 OOP 中, 咱们以类(class)做为咱们的基本单元, 而 AOP 中的基本单元是 Aspect(切面)

11. AOP 中的 Aspect、Advice、Pointcut、JointPoint 和 Advice 参数分别是什么?
在这里插入图片描述

  • Aspect - Aspect 是一个实现交叉问题的类,例如事务管理。方面能够是配置的普通类,而后在 Spring Bean配置文件中配置,或者咱们可使用 Spring AspectJ 支持使用 @Aspect 注解将类声明为 Aspect。
  • Advice - Advice 是针对特定 JoinPoint 采起的操做。在编程方面,它们是在应用程序中达到具备匹配切入点的特定JoinPoint 时执行的方法。您能够将 Advice 视为 Spring 拦截器(Interceptor)或 Servlet过滤器(filter)。
  • Advice Arguments - 咱们能够在 advice 方法中传递参数。咱们能够在切入点中使用 args()表达式来应用于与参数模式匹配的任何方法。若是咱们使用它,那么咱们须要在肯定参数类型的 advice 方法中使用相同的名称。
  • Pointcut - Pointcut 是与 JoinPoint 匹配的正则表达式,用于肯定是否须要执行 Advice。 Pointcut使用与 JoinPoint 匹配的不一样类型的表达式。Spring 框架使用 AspectJ Pointcut表达式语言来肯定将应用通知方法的 JoinPoint。
  • JoinPoint - JoinPoint 是应用程序中的特定点,例如方法执行,异常处理,更改对象变量值等。在 Spring AOP中,JoinPoint 始终是方法的执行器。

12. AOP 有哪些实现方式?

实现 AOP 的技术,主要分为两大类:

静态代理 - 指使用 AOP 框架提供的命令进行编译,从而在编译阶段就可生成 AOP 代理类,所以也称为编译时加强;编译时编织(特殊编译器实现)类加载时编织(特殊的类加载器实现)。
动态代理 - 在运行时在内存中“临时”生成 AOP 动态代理类,所以也被称为运行时加强。 JDK 动态代理CGLIB
13. Spring AOP and AspectJ AOP 有什么区别?

Spring AOP 基于动态代理方式实现;AspectJ 基于静态代理方式实现。 Spring AOP 仅支持方法级别的 PointCut;提供了彻底的 AOP 支持,它还支持属性级别的 PointCut。

5、最后:

针对最近不少人都在面试,我这边也整理了至关多的面试专题资料,也有其余大厂的面经。但愿能够帮助到你们。

下面的面试题答案都整理成文档笔记。也还整理了一些面试资料&最新2020收集的一些大厂的面试真题(都整理成文档,小部分截图),有须要的能够点击进入暗号CSDN

在这里插入图片描述

在这里插入图片描述