深演智能Java面经

1.线程安全定义

当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些线程将如何交替执行,并且在调用代码中不需要任何额外的同步或协同,这个类都能表现出正确的行为,那么这个类就是线程安全的。

2.Spring全家桶基本概念

Spring

Spring是一个开源容器框架,可以接管web层,业务层,dao层,持久层的组件,并且可以配置各种bean,和维护bean与bean之间的关系。其核心就是控制反转(IOC),和面向切面(AOP),简单的说就是一个分层的轻量级开源框架。
为依赖注入、事务管理、WEB应用、数据访问等提供了核心的支持

SpringMVC

Spring MVC属于SpringFrameWork的后续产品,已经融合在Spring Web Flow里面。
SpringMVC是一种web层mvc框架,用于替代servlet(处理|响应请求,获取表单参数,表单校验等。SpringMVC是一个MVC的开源框架,SpringMVC=struts2+spring,springMVC就相当于是Struts2加上Spring的整合。

Springboot

Springboot是一个微服务框架,延续了spring框架的核心思想IOC和AOP,简化了应用的开发和部署。
Spring Boot是为了简化Spring应用的创建、运行、调试、部署等而出现的,使用它可以做到专注于Spring应用的开发,而无需过多关注XML的配置。提供了一堆依赖打包,并已经按照使用习惯解决了依赖问题--->约定大于配置。

spring springboot开发区别

spring framework的Java Web开发模式:

  1. pom文件中引入相关jar包,包括spring、springmvc、redis、mybaits、log4j、mysql-connector-java 等等相关jar ...
  2. 配置web.xml,Listener配置、Filter配置、Servlet配置、log4j配置、error配置 ...
  3. 配置数据库连接、配置spring事务
  4. 配置视图解析器
  5. 开启注解、自动扫描功能
  6. 配置完成后部署tomcat、启动调试

springboot的Java Web开发模式:

  1. pom.xml配置需要引用的相关jar包
  2. yml中配置数据源,服务器,持久层
  3. springboot启动类加相关注解

SpringClod

Spring Cloud事实上是一整套基于Spring Boot的微服务解决方案。它为开发者提供了很多工具,用于快速构建分布式系统的一些通用模式,例如:配置管理、注册中心、服务发现、限流、网关、链路追踪等。

3.如果让你自己实现一个springboot怎样实现

ConfigurationProperties和AutoConfiguration。因为Spring Boot坚信“约定大于配置”这一理念,所以我们使用ConfigurationProperties来保存我们的配置,并且这些配置都可以有一个默认值,即在我们没有主动覆写原始配置的情况下,默认值就会生效,这在很多情况下是非常有用的。除此之外,starter的ConfigurationProperties还使得所有的配置属性被聚集到一个文件中(一般在resources目录下的application.properties),这样我们就告别了Spring项目中XML地狱。

创建自己的springboot starter

如果你想要自己创建一个starter,那么基本上包含以下几步

  1. 创建一个starter项目,关于项目的命名你可以参考这里
  2. 创建一个ConfigurationProperties用于保存你的配置信息(如果你的项目不使用配置信息则可以跳过这一步,不过这种情况非常少见)
  3. 创建一个AutoConfiguration,引用定义好的配置信息;在AutoConfiguration中实现所有starter应该完成的操作,并且把这个类加入spring.factories配置文件中进行声明
  4. 打包项目,之后在一个SpringBoot项目中引入该项目依赖,然后就可以使用该starter了

4.JVM调优工具使用经验

jstat查看内存回收概况,实时查看各个分区的分配回收情况,jmap查看内存栈,查看内存中对象占用大小,jstack查看线程栈,死锁,性能瓶颈,某个线程使用cpu过高导致服务整体慢等都可以通过在这些命令辅助Linux命令看出来。

5.volatile关键字

volatile的特性

可见性:对一个volatile变量的读,总能获取其他任意线程对该变量最后的写入。

有序性:JMM会限制volatile变量相关的编译器重排序和处理器重排序。

可见性的内存语义

volatile写的内存语义:当写入一个volatile变量的时候,JMM将线程工作内存中的该变量的值刷新到主内存。

volatile读的内存语义:当读取一个volatile变量的时候,JMM首先将该线程工作内存中的这个变量设置为无效,迫使该线程重新从主内存获取最新的有效值。

编译器对于有序性重排序的限制

  1. volatile读写不能被更改顺序
  2. 普通读写之前的volatile读不能被重排序到后面
  3. 普通读写之后的volatile写不能被重排序到前面

内存屏障实现有序性

LoadLoad屏障

对于这样的语句Load1; LoadLoad; Load2,在Load2及后续读取操作要读取的数据被访问前,保证Load1要读取的数据被读取完毕。

StoreStore屏障

对于这样的语句Store1; StoreStore; Store2,在Store2及后续写入操作执行前,保证Store1的写入操作对其它处理器可见。

LoadStore屏障

对于这样的语句Load1; LoadStore; Store2,在Store2及后续写入操作被刷出前,保证Load1要读取的数据被读取完毕。

StoreLoad屏障

对于这样的语句Store1; StoreLoad; Load2,在Load2及后续所有读取操作执行前,保证Store1的写入对所有处理器可见。它的开销是四种屏障中最大的。 在大多数处理器的实现中,这个屏障是个万能屏障,兼具其它三种内存屏障的功能。

JMM内存屏障的插入策略

volatile写操作前面插入一个StoreStore屏障

对比StoreStore屏障的定义,这里的volatile写是那个Store2,该屏障保证在volatile写执行之前,Store1的写入操作对其他处理器可见,那么可以得出,该屏障不仅保证了Store1已经执行完毕(有序性),也保证了可见性。

每个volatile写操作的后面插入一个StoreLoad屏障

对比StoreLoad屏障的定义,这里的volatile写是那个Store1,该屏障也保证了有序性和可见性。其他都是类似的。

每个volatile读操作后面插入一个LoadLoad屏障。

每个volatile读操作后面插入一个LoadStore屏障。

6.cas

cas用来保证操作的原子性操作

Unsafe类中的compareAndSwapInt,是一个native方法,该方法的实现位于unsafe.cpp中


cas.png

先想办法拿到内存地址,再通过Atomic::cmpxchg(x, addr, e)实现比较交换。e是原内存值,x为新值。这个函数在WindowsX86下实现如下:

inline jint Atomic::cmpxchg (jint exchange_value, volatile jint* dest, jint compare_value) {
    int mp = os::isMP(); #判断是否是多处理器
    _asm {
        mov edx, dest  #变量内存位置放edx
        mov ecx, exchange_value  #要更新的值放ecx
        mov eax, compare_value #原内存值放eax
        LOCK_IF_MP(mp) #决定是否Lock
        #这句是真正的CAS操作
        cmpxchg dword ptr [edx], ecx
        # dword ptr 将 [edx] 强制类型转换成双字
        # cmpxchg 将 eax 里 内存原值 与(转换后的)对象值 比较
        # 如果相等,就是没别的线程在改变这个对象,那么这个线程就可以改了,将ecx值更新到这个对象。
    }
}

如果是多处理器,LOCK_IF_MP(mp)为cmpxchg指令添加lock前缀。反之,就省略lock前缀。(单处理器会不需要lock前缀提供的内存屏障效果)

7.单例模式

  1. 懒汉饿汉
  2. 枚举实现
  3. 双重校验

双重校验使用volatile关键字的原因

假如有两个并发线程a、b,a线程主动调用了静态方法getInstance(),这时开始加载和初始化该类的静态变量,b线程调用getInstance()并等待获得同步锁,当a线程初始化对象过程中,到了第二阶段即连接阶段的准备步骤时,静态变量doubleKey 被赋予了一个默认值,但是这时还没有进行初始化,这时当a线程释放锁后,b线程判断doubleKey != null,则直接返回了一个没有初始化的doubleKey 对象,问题就出现在这里了,b线程拿到的是一个被赋予了默认值但是未初始化的对象,刚刚可以通过锁的检索!

8.隔离级别

四种隔离级别,举例说明

mysql的隔离级别实现

MySQL默认使用rr的隔离级别

RR使用gap lock来解决幻读问题

MySQL RR/RC区别

简单来说,semi-consistent read是read committed与consistent read两者的结合。一个update语句,如果读到一行已经加锁的记录,此时InnoDB返回记录最近提交的版本,由MySQL上层判断此版本是否满足 update的where条件。若满足(需要更新),则MySQL会重新发起一次读操作,此时会读取行的最新版本(并加锁)。semi-consistent read只会发生在read committed隔离级别下,或者是参数innodb_locks_unsafe_for_binlog被设置为true(该参数即将被废弃)。

对比RR隔离级别,update语句会使用当前读,如果一行被锁定了,那么此时会被阻塞,发生锁等待。而不会读取最新的提交版本,然后来判断是否符合where条件。

半一致性读的优点:
减少了update语句时行锁的冲突;对于不满足update更新条件的记录,可以提前放锁,减少并发冲突的概率。

9.什么时候OOM什么时候stackoverflow

OOM的情况

  1. 给应用程序分配的内存不够,只能通过增大内存来解决.
  2. 内存泄漏.有一部分内存"无用"了,但是因为编码问题导致的没有被垃圾回收掉,产生了泄漏,最终导致了内存溢出(OOM).

stackoverflow的情况

  1. 无限的递归,相当于你的参数无限多,那么栈放不下.
  2. 局部变量太大了,正常分配的栈空间(1M)不够用.
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,009评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,808评论 2 378
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,891评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,283评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,285评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,409评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,809评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,487评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,680评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,499评论 2 318
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,548评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,268评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,815评论 3 304
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,872评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,102评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,683评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,253评论 2 341

推荐阅读更多精彩内容

  • 该文章属于《Java并发编程》系列文章,如果想了解更多,请点击《Java并发编程之总目录》 前言 在前面的文章中,...
    AndyJennifer阅读 1,389评论 1 2
  • 目录: 1. 指令重排 2. 顺序一致性 3. volatile 4. final 1.指令重排 要了解指令重排,...
    西部小笼包阅读 737评论 0 1
  • 九种基本数据类型的大小,以及他们的封装类。(1)九种基本数据类型和封装类 (2)自动装箱和自动拆箱 什么是自动装箱...
    关玮琳linSir阅读 1,870评论 0 47
  • 第2章 java并发机制的底层实现原理 Java中所使用的并发机制依赖于JVM的实现和CPU的指令。 2.1 vo...
    kennethan阅读 1,387评论 0 2
  • Java SE 基础: 封装、继承、多态 封装: 概念:就是把对象的属性和操作(或服务)结合为一个独立的整体,并尽...
    Jayden_Cao阅读 2,091评论 0 8