代码改变世界

2019面试总结

2019-05-22 12:08  晨曦曙光  阅读(532)  评论(0编辑  收藏  举报

1.线程和进程的定义 

   定义:

  进程:是并发执行的程序在执行过程中分配和管理资源的基本单位,是一个动态概念,竞争计算机系统资源的基本单位。

  线程:是进程的一个执行单元,是进程内科调度实体。比进程更小的独立运行的基本单位。线程也被称为轻量级进程。

  注:一个程序至少一个进程,一个进程至少一个线程。

   区别: 

  地址空间:同一进程的线程共享本进程的地址空间,而进程之间则是独立的地址空间

  资源拥有:同一进程内的线程共享本进程的资源如内存、I/O、cpu等,但是进程之间的资源是独立的 

   优缺点: 

  线程执行开销小,但是不利于资源的管理和保护。线程适合在SMP机器(双CPU系统)上运行。

  进程执行开销大,但是能够很好的进行资源管理和保护。进程可以跨机器前移。 

 使用场景:

  对资源的管理和保护要求高,不限制开销和效率时,使用多进程。

  要求效率高,频繁切换时,资源的保护管理要求不是很高时,使用多线程

 

2.NIO和AIO的区别;

  AIO 是彻底的异步通信。
       NIO 是同步非阻塞通信。 
3.HTTP协议、TCP协议、IP协议和TCP/IP协议区别
 

  TCP/IP:协议叫做网络通信协议,它包括上百个协议,而HTTP协议、TCP协议、IP协议只是TCP/IP协议中的一部分. 

  TCP协议:是一种面向连接的、可靠的、基于字节流的{传输层}通信协议 

注:tcp链接需要三次握手: 

  (1)第一次握手:Client将标志位SYN置为1,随机产生一个值seq=J,并将该数据包发送给Server,Client进入SYN_SENT状态,等待Server确认。 

  (2)第二次握手:Server收到数据包后由标志位SYN=1知道Client请求建立连接,Server将标志位SYN和ACK都置为1,ack=J+1,随机产生一个值seq=K,并将该数据包发送给Client以确认连接请求,Server进入SYN_RCVD状态。 

  (3)第三次握手:Client收到确认后,检查ack是否为J+1,ACK是否为1,如果正确则将标志位ACK置为1,ack=K+1,并将该数据包发送给Server,Server检查ack是否为K+1,ACK是否为1,如果正确则连接建立成功,Client和Server进入ESTABLISHED状态,完成三次握手,随后Client与Server之间可以开始传输数据了 

注:tcp 关闭需要4次挥手: 

1)第一次挥手:Client发送一个FIN,用来关闭Client到Server的数据传送,Client进入FIN_WAIT_1状态。 

(2)第二次挥手:Server收到FIN后,发送一个ACK给Client,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号),Server进入CLOSE_WAIT状态。 

(3)第三次挥手:Server发送一个FIN,用来关闭Server到Client的数据传送,Server进入LAST_ACK状态。 

(4)第四次挥手:Client收到FIN后,Client进入TIME_WAIT状态,接着发送一个ACK给Server,确认序号为收到序号+1,Server进入CLOSED状态,完成四次挥手。 


 IP协议:是无连接的通信协议,负责将每个包路由至它的目的地。 

HTTP协议:是一个属于应用层的面向对象的协议,由于其简捷、快速的方式,适用于分布式超媒体信息系统 

4.kafka的架构和几个模块组成 

    Broker:Kafka 集群包含一个或多个服务器,这种服务器被称为 broker。 

    Topic:每条发布到 Kafka 集群的消息都有一个类别,这个类别被称为 Topic。

    Partition:Partition 是物理上的概念,每个 Topic 包含一个或多个 Partition。

    Producer:负责发布消息到 Kafka broker。 

   Consumer:消息消费者,向 Kafka broker 读取消息的客户端。 

   Consumer Group:每个 Consumer 属于一个特定的 Consumer Group(可为每个 Consumer 指定 group name,若不指定 group name 则属于默认的 group)。 

5.ioc是什么,有几种注入方式 

    IOC:所谓IoC,对于spring框架来说,就是由spring来负责控制对象的生命周期和对象间的关系 
5.2注入方式: 
(1)使用属性的setter方法注入 这是最常用的方式(xml注入dao层); 

(2)使用构造器注入; 

(3)使用Filed注入(用于注解方式) 

主要有四种注解可以注册bean,每种注解可以任意使用,只是语义上有所差异:
   @Component:可以用于注册所有bean 

   @Repository:主要用于注册dao层的bean 

   @Controller:主要用于注册控制层的bean 

    @Service:主要用于注册服务层的bean 


6.hashmap和hashtab的区别 

     hashtab:底层数组+链表实现,无论key还是value都不能为null,线程安全,实现线程安全的方式是在修改数据时锁住整个HashTable,效率低 

    hshmap:底层数组+链表实现,可以存储null键和null值,线程不安全 

7.MySQL优化 

1. 为查询缓存优化你的查询

2.字段建索引

3.避免 SELECT *

4.远为每张表设置一个ID

5.用 ENUM 而不是 VARCHAR

6.可能的使用 NOT NULL

7固定长度的表会更快

8 拆分大的 DELETE 或 INSERT 语句

9 设计合适的索引,基于主键的查找,上亿数据也是很快的;
10反范式化设计,以空间换时间,避免join,有些join操作可以在用代码实现,没必要用数据库来实现;
11buffer,尽量让内存大于数据.

8.netty的架构

  Netty是基于Java NIO client-server的网络应用框架,使用Netty可以快速开发网络应用,例如服务器和客户端协议。Netty提供了一种新的方式来开发网络应用程序,这种新的方式使它很容易使用和具有很强的扩展性。Netty的内部实现是很复杂的,但是Netty提供了简单易用的API从网络处理代码中解耦业务逻辑。Netty是完全基于NIO实现的,所以整个Netty都是异步的 。

 

9同步、异步,同步阻塞、同步非阻塞 

  同步和异步: 

同步:在发出一个同步调用时,在没有得到结果之前,该调用就不返回。

 

异步:在发出一个异步调用后,调用者不会立刻得到结果,该调用就返回了。

 阻塞和非阻塞:  

阻塞调用是指调用结果返回之前,调用者会进入阻塞状态等待。只有在得到结果之后才会返回。

非阻塞调用是指在不能立刻得到结果之前,该函数不会阻塞当前线程,而会立刻返回。

  并发和并行:

并发是指一个时间段内,有几个程序都在同一个CPU上运行,但任意一个时刻点上只有一个程序在处理机上运行。

并行是指一个时间段内,有几个程序都在几个CPU上运行,任意一个时刻点上,有多个程序在同时运行,并且多道程序之间互不干扰

 

10.rocitmq和kafka的区别以及Kafka的性能 

11.javaMap的遍历方式 

12.es不适用什么场景 

14.int[] arr=new int[0]打印的是对象还是引用 

15.MySQL引擎的区别 

16.MySQL使用个8个lift jion会怎么样 

17.秒杀架构的设计 

19.arrysList边遍历边删除值该怎么做(使用同一个list) 

20.mysql 的分库和分表 

21.Java有了垃圾回收机制为什么还会出现内存泄漏 

22.linux系统的模块 

  linux系统一般分为4个主要部分:内核、shell+库、文件系统和应用.

23.在数据量单线程能满足的情况下使用单线程好,还是多线程好。 

思路:多线程的线程调用十分耗cpu,多线程调用线程的调用要保存起来所以耗费内存 

24.springcloud和duboo的区别 

  通信方式:

dubbo是纯粹的RPC框架,实现远程服务调用。spring cloud采用的是其于HTTP 的 REST方式。 严格来说,这两种方式各有优劣。虽然从一定程度度上来说,后者牺牲了服务调用的性能,但也避免了上面提到的原生RPC带来的问题。

而且REST相比RPC更为灵活,服务提供方和调用方的依赖只依堂一纸契约,不存在代码级的强依赖,这在强调快速微服务环境下,显得更加合适。这也是dubbo和spring cloud最本质的区别

架构:

spring cloud比dubbo的功能更完善,涵盖更广,而且作为spring的拳头产品,它能与spring framework,spring boot,springdata等其他spring项目完美融合,使用dubbo就像组装电脑,各个环节的自由度很高,例如注册中心,可以用zookeeper,redis等。spring cloud就像品牌机,在spring source的整合下,做了大量的兼容性测试,保证了机器拥有更高的稳定性

 

25.MySQL和postgresql的区别 

     PG相对于MySQL的优势:

1、在SQL的标准实现上要比MySQL完善,而且功能实现比较严谨;

2、存储过程的功能支持要比MySQL好,具备本地缓存执行计划的能力;

3、对表连接支持较完整,优化器的功能较完整,支持的索引类型很多,复杂查询能力较强;

4、PG主表采用堆表存放,MySQL采用索引组织表,能够支持比MySQL更大的数据量。

5、PG的主备复制属于物理复制,相对于MySQL基于binlog的逻辑复制,数据的一致性更加可靠,复制性能更高,对主机性能的影响也更小。

6、MySQL的存储引擎插件化机制,存在锁机制复杂影响并发的问题,而PG不存在。

 

   MySQL相对于PG的优势:

1、innodb的基于回滚段实现的MVCC机制,相对PG新老数据一起存放的基于XID的MVCC机制,是占优的。新老数据一起存放,需要定时触 发VACUUM,会带来多余的IO和数据库对象加锁开销,引起数据库整体的并发能力下降。而且VACUUM清理不及时,还可能会引发数据膨胀;

2、MySQL采用索引组织表,这种存储方式非常适合基于主键匹配的查询、删改操作,但是对表结构设计存在约束;

3、MySQL的优化器较简单,系统表、运算符、数据类型的实现都很精简,非常适合简单的查询操作;

4、MySQL分区表的实现要优于PG的基于继承表的分区实现,主要体现在分区个数达到上千上万后的处理性能差异较大。

5、MySQL的存储引擎插件化机制,使得它的应用场景更加广泛,比如除了innodb适合事务处理场景外,myisam适合静态数据的查询场景。

 

总体上来说,开源数据库都不是很完善,商业数据库oracle在架构和功能方面都还是完善很多的。从应用场景来说,

PG更加适合严格的企业应用场景(比如金融、电信、ERP、CRM),

而MySQL更加适合业务逻辑相对简单、数据可靠性要求较低的互联网场景(比如google、facebook、alibaba)

 

26.jvm(java)的内存结构

    JVM把内存划分成了如下几个区域:

 

1.方法区(Method Area):方法区存放了要加载的类的信息(如类名、修饰符等)、静态变量、构造函数、final定义的常量、类中的字段和方法等信息。方法区是全局共享的,在一定条件下也会被GC。当方法区超过它允许的大小时,就会抛出OutOfMemory:PermGen Space异常。

2.堆区(Heap): 堆区是GC最频繁的,也是理解GC机制最重要的区域。堆区由所有线程共享,在虚拟机启动时创建。堆区主要用于存放对象实例及数组,所有new出来的对象都存储在该区域。

3.虚拟机栈(VM Stack):   虚拟机栈占用的是操作系统内存,每个线程对应一个虚拟机栈,它是线程私有的,生命周期和线程一样,每个方法被执行时产生一个栈帧(Statck Frame),栈帧用于存储局部变量表、动态链接、操作数和方法出口等信息,当方法被调用时,栈帧入栈,当方法调用结束时,栈帧出栈。

 注:虚拟机栈定义了两种异常类型:StackOverFlowError(栈溢出)和OutOfMemoryError(内存溢出)。如果线程调用的栈深度大于虚拟机允许的最大深度,则抛出StackOverFlowError;不过大多数虚拟机都允许动态扩展虚拟机栈的大小,所以线程可以一直申请栈,直到内存不足时,抛出OutOfMemoryError。

 

4.本地方法栈(Native Method Stack):本地方法栈用于支持native方法的执行,存储了每个native方法的执行状态。本地方法栈和虚拟机栈他们的运行机制一致,唯一的区别是,虚拟机栈执行Java方法,本地方法栈执行native方法。在很多虚拟机中(如Sun的JDK默认的HotSpot虚拟机),会将虚拟机栈和本地方法栈一起使用。

5.程序计数器(Program Counter Register):程序计数器是一个很小的内存区域,不在RAM上,而是直接划分在CPU上,程序猿无法操作它,它的作用是:JVM在解释字节码(.class)文件时,存储当前线程执行的字节码行号,只是一种概念模型,各种JVM所采用的方式不一样。字节码解释器工作时,就是通过改变程序计数器的值来取下一条要执行的指令,分支、循环、跳转等基础功能都是依赖此技术区完成的。

引用的种类:

       强引用:new出来的对象都是强引用,GC无论如何都不会回收,即使抛出OOM异常。
       软引用:只有当JVM内存不足时才会被回收。
       弱引用:只要GC,就会立马回收,不管内存是否充足。
       虚引用:可以忽略不计,JVM完全不会在乎虚引用。它唯一的作用就是做一些跟踪记录,辅助finalize函数的使用。

什么样的类会被回收:

a.该类的所有实例都已经被回收;
b.加载该类的ClassLoad已经被回收;
c.该类对应的反射类java.lang.Class对象没有被任何地方引用。

 

GC机制:在上面介绍的五个内存区域中,有3个是不需要进行垃圾回收的:本地方法栈、程序计数器、虚拟机栈。因为他们的生命周期是和线程同步的,随着线程的销毁,他们占用的内存会自动释放。所以,只有方法区和堆区需要进行垃圾回收,回收的对象就是那些不存在任何引用的对象。

内存分区:

         新生代(Youn Generation):大致分为Eden区和Survivor区,Survivor区又分为大小相同的两部分:FromSpace和ToSpace。新建的对象都是从新生代分配内存,Eden区不足的时候,会把存活的对象转移到Survivor区。当新生代进行垃圾回收时会出发Minor GC(也称作Youn GC)。

       旧生代(Old Generation):旧生代用于存放新生代多次回收依然存活的对象,如缓存对象。当旧生代满了的时候就需要对旧生代进行回收,旧生代的垃圾回收称作Major GC(也称作Full GC)。

       持久代(Permanent Generation):在Sun 的JVM中就是方法区的意思,尽管大多数JVM没有这一代。

参考地址:https://blog.csdn.net/anjoyandroid/article/details/78609971

27.Synchronize 和 Lock 的区别

>1.原始构成
 synchronized 是关键字属于JVM层面

  monitorenter(底层是通过monitor对象来完成,其实wait/notify等方法也依赖于monitor对象只有在同步块或方法中才能调wait/notify等方法,)

  monitorexit

Lock是具体类(java.util.concurrent.locks.Lock)是api层面的锁

>2.使用方法

synchronized 不需要用户去手动释放锁,当synchroized代码执行完成后系统会自动让线程释放对锁的占用

ReentrantLock则需要用户去手动释放锁若没有主动释放锁,就有可能导致出现死锁现象。(需要lock()和unlock()方法配合try/finally语句块来完成。)

>3.等待是否可中断

synchronized不可中断,出非抛出异常或者正常运行完成

ReentrantLock可中断:1.设置超时方法try lock(long timeout,TimeUnit unit)2.lockInterruptibly()放代码块中,调用interrupt()方法可中断

>4.加锁是否公平

synchronized是非公平锁

ReentrantLock两者皆可,默认非公平锁,构造方法可以传入boolean值,true为公平锁,false为非公平锁

>5.锁绑定多个条件

synchronized 没有

ReentrantLock用来实现分组唤醒的线程们,可以精确唤醒。而不是像synchronized要么随机唤醒一个线程要么唤醒全部。