作者:OfferOffer多多
链接:https://www.nowcoder.com/discuss/505316?type=post&order=time&pos=&page=1&channel=1009&source_id=search_post
来源:牛客网

面经(三面放在了一起):

计算机网络常规问题:HTTP/HTTPS/TCP/WebSocket协议,长连接短连接,拥塞控制机制,tcp为什么是可靠的等。

答:这些问题感觉写过好多遍,再写一次多多益善

1、 WebSocket:

webSocket协议是基于TCP的一种新的网络协议。它实现了浏览器与服务器全双工通信–允许服务器主动发送信息给客户端。

产生背景:

长久以来, 创建实现客户端和用户端之间双工通讯的web app都会造成HTTP轮询的滥用: 客户端向主机不断发送不同的HTTP呼叫来进行询问。
这会导致一系列的问题:
1.服务器被迫为每个客户端使用许多不同的底层TCP连接:一个用于向客户端发送信息,其它用于接收每个传入消息。

2.有些协议有很高的开销,每一个客户端和服务器之间都有HTTP头。

3.客户端脚本被迫维护从传出连接到传入连接的映射来追踪回复。

一个更简单的解决方案是使用单个TCP连接双向通信。 这就是WebSocket协议所提供的功能。 结合WebSocket API ,WebSocket协议提供了一个用来替代HTTP轮询实现网页到远程主机的双向通信的方法。

WebSocket协议被设计来取代用HTTP作为传输层的双向通讯技术,这些技术只能牺牲效率和可依赖性其中一方来提高另一方,因为HTTP最初的目的不是为了双向通讯。

实现原理:

在实现websocket连线过程中,需要通过浏览器发出websocket连线请求,然后服务器发出回应,这个过程通常称为“握手” 。在 WebSocket API,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。在此WebSocket 协议中,为我们实现即时服务带来了两大好处:

  1. Header

互相沟通的Header是很小的-大概只有 2 Bytes

  1. Server Push

服务器的推送,服务器不再被动的接收到浏览器的请求之后才返回数据,而是在有新数据时就主动推送给浏览器。

使用介绍

在HTML5中内置有一些API,用于响应应用程序发起的请求。基本API语句如下:

创建对象
url为WebSocket服务器的地址,name为发起握手的协议名称,为可选择项。

发送文本消息
msg为文本消息,对于其他类型的可以通过二进制形式发送。

2、TCP

传输控制协议是互联网协议组的主要协议之一。TCP在通过IP网络通信的主机上运行的应用程序之间提供可靠、有序且经过错误检查的八位字节流传递

应用层次:传输层
数据格式:字节流
工作:与IP协议共同使用
服务:由套接字端点获得

特点:
  • 面向连接
  • 每一条TCP连接只能是点对点(一对一);
  • 提供可靠交付的服务:通过TCP连接传输的数据,无差错、不重复、不丢失
  • 提供全双工通信
  • 面向字节流
  • TCP首部占20个字节

TCP首部格式:源端口,目的端口,序号,确认号,数据偏移,保留,紧急URG,确认ACK,推送PSH,复位RST,同步SYN,终止FIN,窗口,检验和,紧急指针,选项。

3、HTTP

HTTP协议,超文本传输协议。是一种详细规定了浏览器和万维网服务器之间通信的规则,通过因特网传送万维网文档的数据传送协议

应用层次:应用层协议
默认端口:80

特点

1、简单快速
2、灵活
3、http0.9和http1.0使用非持续;http1.1使用持续协议
4、无状态:指协议对于事务处理没有记忆功能

工作流程

采用请求/响应模型。客户端向服务器发送一个请求报文,请求报文包含了请求的方法、URL、协议版本、请求头部和请求数据。
服务器以一个状态行作为响应,响应的内容包括协议的版本、成功或者错误的代码、服务器信息、响应头部和响应数据。

4、HTTPS

HTTPS是以安全为目标的HTTP通道,在HTTP的基础上通过传输加密和身份认证保证了传输过程的安全性。HTTPS在HTTP的基础下加入SSL层,是HTTPS的安全基础,因此加密的详细内容就是需要SSL。HTTPS存在不同于http的默认端口及一个加密/身份验证层。这个系统提供了身份验证与加密通讯方法。被广泛用于万维网上安全敏感的通讯,例如交易支付等方面。

长连接和短链接

区别

短链接:连接—传输数据—关闭连接

比如HTTP是无状态的短链接,浏览器和服务器每进行一次HTTP操作,就建立一次连接,但任务结束就中断连接

具体:浏览器client发起并建立TCP连接—client发送HttpRequest报文—server接收到报文—server handler并发送HttpResponse 报文给前端,发送完毕后立即调用socket.close()方法—client接收response报文—client最终会收到server端断开TCP连接的信号—client端断开TCP连接,具体就是调用close方法

短链接是指socket连接后,发送接收完数据马上断开连接

因为连接诶后接收了数据就断开了,所以每次数据接受处理不会有联系。这就是http协议无状态的原因之一

长连接:连接—传输数据—保持连接—传输数据—……—直到一方关闭连接,多是客户端关闭连接

长连接指建立socket连接后不管是否使用都保持连接,但安全性较差

长连接和短链接的选择

长连接多用于操作频繁,点对点的通讯,而且连接数不能太多的情况。每个TCP连接都需要进行三次握手,这需要时间,如果每个操作都是先连接,再操作的话那么处理速度会降低很多,所以每个操作完后不断开,下次处理时直接发送数据包就ok了,不用建立TCP连接。例如:数据库的连接用长连接,如果用短链接频繁的通信会造成socket错误,而且频繁的socket创建也是对资源的浪费。

而像web网站的http服务一般都用短链接,因为长连接对于服务端来说会耗费一定的资源,而像web网站这么频繁的成千上万客户端的连接用短链接会更省一些资源,如果使用长连接,而且同时有成千上万的用户,如果每个用户都占用一个连接的话,那么可想而知占用多少资源。

拥塞控制

在计算机网络中的链路容量(即宽带)、交换结点中的缓存和处理机等,都是网络的资源。在某段时间,若对网络中某一资源的需求超过了该资源所提供的可用部分,网络的性能就要变坏。这种情况就叫拥塞,可以把出现网络拥塞的条件写成如下关系式

若网络中有许多资源同时呈现供应不足,网络的性能就要变坏,整个网络的吞吐量会随着负荷的增大而下降。

而解决问题需要定位原因,但是网络拥塞往往是由诸多因素引起的,往往需要达到各个部分的平衡。

拥塞控制与流量控制的关系密切:所谓拥塞控制就是防止过多的数据注入到网络中,这样可以使网络中的路由器或链路不致过载。拥塞控制所要做的都有一个前提,就是网络能够承受现有的网络负荷。

拥塞控制是一个全局性的过程,涉及到所有的主机、路由器,以及与降低网络传输性能有关的所有因素。但TCP连接的端点只要迟迟不能收到对方的确认信息,就猜想在当前网络中的某处可能发生了拥塞,但这时却无法知道拥塞发生的地方和具体原因。

相反流量控制往往是指点对点通信量的控制,是个端对端的问题(接收端控制发送端)。流量控制所要做的就是抑制发送端发送数据的速率,以便使接收端来得及接收

拥塞控制和流量控制之所以常常被弄混,是因为某些拥塞控制算法是向发送端发送控制报文,并告诉发送端,网络已经出现麻烦,必须放慢速率。折点和流量控制有点像

进行拥塞控制需要付出代价。这首先需要获得网络内部流量分布的信息。在实施拥塞控制时,还需要在结点之间交换信息和各种命令,以便选择控制的策略和实施控制。这样就产生了额外开销。拥塞控制有时需要将一些资源分配给个别用户(或一些类别的用户)单独使用,这样就使网络资源不能更好的实现共享。在设计拥塞控制策略时,必须全面衡量得失。

理论上讲,解决拥塞控制就是寻找上述公式的破坏条件。这或者是增大网络的某些可用资源(如业务繁忙时增加一些链路,增大链路的宽带,或使额外的通信量从另外的通路分流),或减少一些用户对资源的需求(如拒绝接受新的建立连接的请求,或要求用户减轻其负荷,这属于降低服务质量)。必须考虑影响。

实践证明,拥塞控制是很难设计的,因为是一个动态的问题。当前网络正朝着高速化的方向发展,这很容易出现缓存不够大而造成分组的丢失。但分组的丢失是网络发生拥塞的征兆而不是原因。在许多情况下,甚至正是拥塞控制机制本身成为引起网络性能恶化甚至发生死锁的原因。应该引起重视

由于计算机网络是一个很复杂的系统,因此可以从控制理论的角度来看拥塞控制这个问题。从大的方面看,可以分为开环控制和闭环控制两种方法。开环控制就是设计网络时事先将有关发生拥塞的因素考虑周到,一旦运行起来中途不再更改。
闭环控制是基于反馈环路的概念,主要有以下措施:

  • 监测网络系统以便检测到拥塞在何时何处发生;
  • 把拥塞发生的信息传送到可采取行动的地方;
  • 调整网络系统的运行以解决出现的问题;

有很多的方法可用来监测网络的拥塞。主要的一些指标是:由于缺少缓存空间而被丢弃的分组的百分数、平均队列长度、超时重传的分组数、平均分组时延、分组时延标准差。

TCP的拥塞控制方法

TCP进行拥塞控制的算法有四种,即慢开始、拥塞避免、快重传和快恢复。

判断网络拥塞的依据就是出现了超时

  • 慢开始:当主机开始发送数据时,由于并不清楚网络的负荷情况,所以如果立即把大量数据字节注入到网络,那么就有可能引起网络发送拥塞。慢开始的核心思想就是由小到大逐渐增大拥塞窗口数值
    旧的规定在刚刚开始发送报文段时,先把初始拥塞窗口cwnd设置为1至2个发送方的最大报文段SMSS的数值,
    新的规定初始拥塞串口cwnd设置不得超过2至4个SMSS的数值


    其中N是原先未被确认的、但现在被刚收到的确认报文段所确认的字节数。采用这种方式更加合理。
    开始是cwnd=1,每经过一个传输轮次,拥塞窗口就加倍;

    传输轮次:把拥塞窗口cwnd所允许发送的报文段都连续发送出去,并收到了对己发送的最后一个字节的确认。这个慢开始的慢指的是先将cwnd设为1,然后逐渐增大cwnd。
  • 拥塞避免:算法思想是让拥塞窗口cwnd缓慢的增大,即没经过一个往返时间RTT就把发送发的拥塞窗口cwnd加1,而不是像慢开始阶段那样加倍增长。因此在拥塞避免阶段就有加法增大的特点。这表明在拥塞避免阶段,拥塞窗口cwnd按线性规律缓慢增长,比慢开始算法的拥塞窗口增长速率缓慢得多。

    这张图很清楚地展示了慢开始和拥塞避免的过程
  • 快重传算法:算法思想是首先要求接收方不要等待自己发送数据时才进行捎带确认,而是要立即发送确认,即使收到了失序的报文段也要立即发出对已收到的报文段的重复确认。可以让发送方尽早知道发生了个别报文段的丢失。

只要发送方一连收到3个重复确认,就知道接收方确实没有收到报文段M3,因而需要立即重传

  • 快恢复:发送方调增门限值,同时设置拥塞窗口,并开始执行拥塞避免算法。
    如上图所示,发送方知道现在只是丢失了个别的报文段,于是不启动慢开始,而是执行快恢复算法

TCP为什么是可靠的

答:TCP可靠传输的工作原理是:1、停止等待协议;2、连续ARQ协议3、滑动窗口协议;4、TCP首部报文格式

停止等待协议
    全双工通信的双方既是发送方也是接收方。停止等待就是每发送完一个分组就停止发送,等待对方的确认。在收到确认后再发生下一个分组。分为三种情况:(1)无差错情况:发送后等待确认再发送下一个;(2)出现差错:A超过一段时间没收到确认,就认为刚才发送的分组丢失了,因而重传发送过的分组,这就叫做超时重传。超时重传的实现注意点:a、必须暂时保留已发送的分组的副本b、分组和确认分组都必须进行编号c、超时计时器设置的重传时间应当比数据在分组传输的平均往返时间更长一些。(避免不必要的重传)(3)确认丢失和确认迟到,A重传,若收到重复的确认收下就丢弃;B丢弃重复的M1,并重传确认分组。停止等待协议的优点是简单,缺点就是信道利用率太低,为了提高效率可以使用流水线传输,需要用到以下协议连续ARQ协议和滑动窗口协议
连续ARQ协议
    位于发送窗口内的5个分组都可以连续发送出去,而不需要等待对方的确认。这样,信道利用率就提高了;协议规定发送方每收到一个确认,就把发送窗口向前滑动一个分组的位置;接收方一般是采用累积确认的方式,接收方不必逐个发送确认,对按序到达的最后一个分组发送确认表示到这个分组为止所有的分组都已经正确收到了。优点:容易实现,即使确认丢失也不必重传。缺点:不能向发送方反映出接收方已经正确收到的所有分组的信息。
TCP首部结构
     TCP的报文段首部格式是TCP的可靠传输的基石。首部结构:源端口和目的端口、序号、确认号(期望收到对方下一个报文段的第一个数据字节的序号)、数据偏移、保留、紧急URG、确认ACK、推送PSH、复位RST、同步SYN、终止FIN、窗口(指发送本报文段的一方的接受窗口(而不是自己的发送窗口)窗口值作为接收方让发送方设置其发送窗口的依据)、检验和、紧急指针、选项
滑动窗口协议
      这里需要注意TCP是全双工通信,既是发送方也是接收方;假设A发送数据B给出确认。以字节为单位的滑动窗口主要由以下几点来保证传输可靠性。为了防止发送方发送过多的数据而接收方无法接受导致异常
  • 1、A的发送窗口是根据B的接受窗口设置的
  • 2、对于不按序到达的数据先临时存放在接受窗口中,等到字节流中所缺少的字节确认收到后,按序交付上层的应用进程
  • 3、TCP要求接收方必须有累积确认的功能,这样可以减少传输开
  • 4、超时重传的时间选择:Kam算法:在计算加权平均RTTS时,只要报文段重传了,就不采用其往返时间样本。这样得出的加权平均RTTS和RTO就比较准确;报文段每重传一次,就把超时重传时间RTO增大一些。典型的做法是取新的重传时间为旧的重传时间的2倍。
  • 5、选择确认SACK:当收到的报文段未按序号时就进行选择确认。可以将已经传输过来的报文段的边界信息发送给发送端,要使用SACK时需要双方事先商定好,允许SACK设置,但是这样很容易超出选项长度40个字节的上限。SACK文档并没有指明发送方应当怎样响应SACK,因此大多数时候还是重传所有未被确认的数据块。

操作系统常规问题:线程与进程区别。线程调度机制,进程的状态,死锁的条件等

答:

1、线程调度机制

线程调度机制有两种:抢占式线程调度、协作式线程调度
那么java中的线程调度是什么呢?
《深入理解java虚拟机》一书中所说的java采用抢占式线程调度

从以上Java在不同平台上的实现来看,只有在底层平台不支持线程时,JVM才会自己实现线程的管理和调度,此时Java线程以绿色线程的方式运行。由于目前流行的操作系统都支持线程,所以JVM就没必要管线程调度的事情了。应用程序通过setPriority()方法设置的线程优先级,将映射到内核级线程的优先级,影响内核的线程调度。

目前的Java的官方文档中几乎不再介绍有关Java线程的调度算法问题,因为这确实不是Java的事儿了。尽管程序中还可以调用setPriority(),提请JVM注意线程的优先级,但你千万不要把这事儿太当真。Java中所谓的线程调度仅是底层平台线程调度的一个影子而已。

由于Java是跨平台的,因此要求Java的程序设计不能对Java线程的调度方法有任何假设,即程序运行的正确性不能依赖于线程调度的方法。所以说程序员最好不要过分关心底层平台是如何实现线程调度的

2、线程与进程的区别

  • 根本区别:进程是操作系统资源分配的基本单位,而线程是处理器任务调度和执行的基本单位
  • 资源开销:每个线程都有独立的代码和数据空间(程序上下文),程序之间的切换会有较大的开销;线程可以看做是轻量级的进程,同一类线程共享代码和数据空间,每个线程都有自己独立的运行栈和程序计数器(PC),线程之间切换的开销小。
  • 包含关系:如果一个进程内有多个线程,则执行过程不是一条线的,而是多条线共同完成;线程是进程的一部分,所以线程也被称为轻权进程或者轻量级进程。
  • 内存分配:同一进程的线程共享本进程的地址空间和资源,而进程之间的地址空间和资源是相互独立的
  • 影响关系:一个进程奔溃后,在保护模式下不会对其他线程产生影响,但是一个线程崩溃整个线程都死掉。所以多进程要比多线程健壮。
  • 执行过程:每个独立的进程有程序运行的入口,顺序执行序列和程序出口。但是线程不能独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制,两者均可并发执行

3、进程的状态

  • 创建状态:进程在创建时需要申请一个空白PCB,向其中填写控制和管理进程的信息,完成资源分配。如果创建工作无法完成,比如资源无法满足,就无法被调度运行,把此时进程所处状态称为创建状态
  • 就绪状态:进程已经准备好,已分配到所需资源,只要分配到CPU就能够立即运行
  • 执行状态:进程处于就绪状态被调度后,进程进入执行状态
  • 阻塞状态:正在执行的进程由于某些事件(IO请求,申请缓存区失败)而暂时无法运行,进程收到阻塞。在满足请求时进入就绪状态等待系统的调度
  • 终止状态:进程结束,或出现错误,或被系统终止,进入终止状态,无法继续执行

4、死锁的条件

1、互斥条件
2、不可剥夺条件
3、请求与保持条件
4、循环等待条件

问了一大堆Linux使用的问题,好多都不会。

JDK调优工具:jps, jstack, jmap啥的。

JVM内存区域,分代模型,什么时候会发生OOM

答:

1、分代模型:年轻代,老年代

我们不同的代码编写方式,决定 了这些对象的生存周期
所以JVM将java堆内存划分为两个区域,一个是年轻代,一个是老年代
年轻代就是存放那种使用完就马上回收的对象
老年代是用来存放哪些长期驻留在内存汇总的对象。

为什么这样分呢?

与垃圾回收机制有关,对于存活时间短的和长期存活的对象,回收算法是不一致的

2、JVM内存区域

java运行时数据区域:

  • 1、程序计数器

         一块较小的内存区域,可以看做当前线程执行字节码的行号指示器。1.1作用(1)字节码解释器通过改变程序计数器来依次读取指令,从而实现代码的流程控制,如顺序执行、选择循环、异常处理……(2)在多线程情况下,程序计数器用于记录当前线程的执行位置,从而当线程被切换回来的时候能够知道该线程上次运行的位置。1.2是否线程共享线程私有1.3生命周期随着线程的创建而创建,随着线程的结束而死亡1.4抛出异常唯一一个不会出现OOM异常的内存区域
    
  • 2、java虚拟栈

       描述的是java方法执行的内存模型;由一个个栈帧组成,栈帧由(局部变量表,操作数栈,动态链接,方法出口信息)组成2.1作用每一个方法在执行的同时都会创建一个栈帧,用于存储局部变量表,操作数栈,动态链接,方法出口等信息,一个方法从调用知道执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈和出栈的过程。2.2是否线程共享线程私有2.3生命周期随着线程的创建而创建,随着线程的结束而死亡2.4抛出异常(1)栈溢出异常(2)OOM异常
    
  • 3、本地方法栈

     3.1作用和虚拟机栈发挥的作用的相似,但是虚拟机栈是为虚拟机执行java方法而服务的,本地方法栈是为虚拟机执行Native方法而服务的。
    3.2是否线程私有不是线程私有3.3生命周期3.4抛出异常(1)爆栈(2)OOM
    
  • 4、堆

    java虚拟机下所管理的最大的一块java堆是所有线程共享的一块内存区域,在虚拟机启动时创建
    java堆是垃圾收集管理的主要区域,因此很多时候也被称为GC堆4.1作用存放对象实例,几乎所有的对象实例以及数组都是在这里分配内存(运行时的对象)
    4.2是否线程私有
    

    不是线程私有
    4.3生命周期
    4.4抛出异常
    如果在堆中没有内存完成实例分配并且堆也无法再扩展时会抛出
    OOM异常

  • 5、方法区

      5.1作用用于存储已被虚拟机加载的类信息、常量、静态变量、及时编译器编译之后的代码(类型数据)5.2是否线程私有不是线程私有5.3生命周期整个程序的生命周期5.4抛出异常当方法区无法满足内存分配的需要时会抛出OOM异常
    
  • 6、运行时常量池

        注意:已经明确的一点是 字符串常量池、静态变量 在jdk7时从方法区移入**Java堆**中,那么运行时常量池呢?我看了jdk6/7/8三版jvm文档,对运行时常量池的描述都是方法区的一部分作用:用于存放编译期生成的字面量和符号引用,这部分内容将在类加载之后进入方法区中的运行常量池中存放。当常量池无法申请到内存时会抛出OOM异常
    
  • 7、直接内存

     直接内存并不是虚拟机运行时数据区域的一部分,也不是java虚拟机规范中定义的内存,但是这部分内存也被频繁使用,也可能导致OOM异常
    

3、什么时候会发生OOM异常

https://blog.csdn.net/Fly_Fly_Zhang/article/details/89741569?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.edu_weight&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.edu_weight

  • java堆空间
  • GC开销超过限制
  • 请求的数组大小超过虚拟机限制
  • Perm gen空间
  • Metaspace
  • 无法新建本机线程
  • 发生了Stack_trace_with_native_method

类加载器,双亲委派模型,类加载机制

答:

GC垃圾回收算法,分代回收算法,四大引用类型

答:

MySQL语法,写了两个个SQL题目,如果一个表非常大,一个表很小,怎么优化查询效率

答:小表驱动大表,小表建立主键,尽量使用exits

1、优化sql和索引
2、加缓存,memcached,redis
3、主从复制或主主复制,读写分离
4、使用MySQL自带的分区表
5、垂直拆分
6、水平切分

索引,索引的数据结构(抛开MySQL来说),Mysql中的索引,聚集索引和系数索引,最左匹配原则,如何调优SQL

MySql中的锁分类,InnoDB和MyISAM的区别和分别适用的场景,事务的四大特性,四大隔离级别,怎么避免幻读?

MySQL中的redo log和bin log。

答:

Redis是干什么用的?Redis如何实现分布式锁?Redis的持久化机制?Redis可能会出现的问题(雪崩、穿透等)。Redis的数据结构,跳表。

答:

一致性哈希算法,用来干什么?

答:

多线程是什么?为什么需要多线程?什么情况下需要多线程?

答:

线程安全是什么?volatile了解么,干什么用的,原理是什么?synchronized呢?

答:

线程池,线程池的参数,线程池提交一个任务后的的运行过程,什么时候会触发饱和策略?项目中用过线程池没有,怎么保证线程安全的?

答:

JUC包中的工具类,CAS机制

答:
java并发包java.util.concurrent。java并发包包括java.util.concurrent、java.util.concurrent.atomic、java.util.concurrent.locks包

java从1.5开始引入并发包。其中java.util.concurrent.atomic包,方便在无锁的情况下,进行原子操作。原子变量的底层使用是CPU的原子指令,但是不同的CPU有不同的架构,指令不同。所以也有可能需要提供某种内部的锁机制。所以不能保证线程绝对不会阻塞。

Atomic分类

1、原子更新基本类型
  • AtomicBoolean 原子更新布尔类型
  • AtomicInterger 原子更新整型
  • AtomicLong 原子更新长整型

原子更新整型的常用方法:

  • int get(); 获取当前值

  • void set(int newValue); 设置为给定值

  • int getAndAdd(int delta); 以原子方式将给定值与当前值相加

  • int decrementAndGet(); 以原子方式将当前值减一

  • int incrementAndGet(); 以原子方式将当前值加一

  • void lazySet(int newValue); 最后设置为给定值

  • AtomicInteger:整型原子类

  • AtomicLong:长整型原子类

  • AtomicBoolean:布尔型原子类

为什么原子类型的操作就是线程安全的呢?底层如何操作?
对JVM有所了解的应该知道CAS操作。CAS操作有3个操作数,内存值M,预期值E,新值U,如果M==E,则将内存值修改为B,否则啥都不做。就是当且仅当内存值与当前值一致,才进行值的更新。否则不更新,这样就保证了atomic包下面的操作的原子行。

public class AtomicInteger extends Number implements java.io.Serializable {private static final long serialVersionUID = 6214790243416807050L;// setup to use Unsafe.compareAndSwapInt for updatesprivate static final Unsafe unsafe = Unsafe.getUnsafe();private static final long valueOffset;static {try {valueOffset = unsafe.objectFieldOffset(AtomicInteger.class.getDeclaredField("value"));} catch (Exception ex) { throw new Error(ex); }}private volatile int value;/*** Creates a new AtomicInteger with the given initial value.** @param initialValue the initial value*/public AtomicInteger(int initialValue) {value = initialValue;}}

源码中可以看到,有一个Unsafe类,一个volatile修饰的value,这个value就是先保证了AtomicInteger操作的可见性。然后Usafe保证对这个value值的操作是CAS操作,这样就保证了原子性。
而Unsafe的CAS方法是比较内存中的值和期望的值,如果相同则更新,此更新不可中断

主要利用CAS和volatile和native方法保证原子操作,避免synchronized的高开销,提高效率

CAS 原理是拿期望的值和原本的值比较,如果相同更新成新的值;是一种系统原语,原语属于操作系统范畴,是由若干条指令组成,用于完成某个功能的一个过程,并且原语的执行必须是连续的,在执行过程中不可中断,也就是说CAS是一条原子指令,不会造成所谓的数据不一致问题。

缺点:1、循环时间长,开销大 ;2、只能保证一个共享变量的原子操作;3、引出来ABA问题 解决方法:使用AtomicReference原子引用

2、原子更新数组类型
  • AtomicIntegerArray
  • AtomicLongArray
  • AtomicReferenceArray

理解了原子更新基本类型,对于其他类型就比较好理解
原理相似,自身拥有一个int[]的数组array。如果我们调用构造器构造的时候没有传入数组,则直接初始化自身数组,否则,对我们的数组进行克隆。也就是说,操作的都是自身的数组,对于我们传入的数组不会有任何操作。而对数组中的数据操作也是通过Unsafe类来实现其原子性的操作。

3、原子更新引用类

AtomicReference

  • AtomicReference:引用类型原子类
  • AtomicStampedRerence:原子更新引用类型里的字段原子类
  • AtomicMarkableReference:原子更新带有标记位的引用类型

原子更新基本类型,每次只能更新一个变量,而当需要更新多个变量,比如一个对象的多个属性的时候,我们必须用到原子更新引用类型类
我们操作的是整个对象。如果对这个对象单独的属性进行操作,会导致对象的原子不一致。

4、原子更新字段

如果我们只需要某个类的字段,那么就需要使用原子更新字段类,Atomic包提供了以下的类:

  • AtomicIntegerFieldUpdater:原子更新整型字段的更新器
  • AtomicLongFieldUpdater:原子更新长整型字段的更新器
  • AtomicStampedReference:原子更新带有版本号的引用类型

字段必须用volatile修饰,字段不能修饰为private

java锁之公平锁和非公平锁,可重入锁,自旋锁,读写锁?

答:

1、公平锁和非公平锁

公平锁:是指多个线程按照申请锁的顺序来获取锁;
非公平锁:是指在多线程获取锁的顺序并不是按照申请锁的顺序,有可能后申请的线程比先申请的线程优先获得锁,在高并发的情况下,有可能造成优先级反转和饥饿问题

并发包ReentrantLock的创建可以指定构造函数的boolean类型来得到公平锁和非公平锁,默认为非公平(原理,等待队列,按照FIFO的规则从队列中取到自己)

2、可重入锁(递归锁)

指的是同一个线程外层函数获得锁之后,内层递归函数仍然能获取该锁的代码,在同一个线程在外层方法获取锁的时候,在进入内层方法会自动获取锁,也就是线程可以进入任何一个它已经拥有的锁所同步的代码块

3、自旋锁(spinlock)

是指尝试获取锁的线程不会立即阻塞,而是采用循环的方式去尝试获取锁,这样的好处是减少线程上下文切换消耗,缺点是循环会消耗CPU

4、读写锁

写写互斥/读写互斥
读读不互斥

读写锁是一种特殊的自旋锁,把对共享资源对访问者划分成了读者和写者,
读者只对共享资源进行访问,写者则是对共享资源进行写操作
读写锁在Reentrantlock上进行了拓展使得该锁更适合读操作远远大于写操作的场景。一个读写锁同时只能存在一个写锁但是可以存在多个读锁,不能同时存在读锁和写锁

java并发之CountDownLatch闭锁详解

https://blog.csdn.net/qq_40709110/article/details/104358887?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.edu_weight&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.edu_weight
CountDownLatch主要有两个方法,当一个或多个线程调用awati方法,调用线程会被阻塞,其他线程调用countDown方法计数器减一,当计数器的值变为0,因调用await方法被阻塞的线程会被唤醒,继续执行

平时开发过程中怎么处理异常的?

答:

项目相关问题,各种处理方式,解决方案。

答:

Spring常用的注解,你这个仿Spring框架的项目大概的一个逻辑是什么样的?Spring AOP应用场景,原理。

答:
使用注解之前要开启自动扫描功能,其中base-package为需要扫描的包(含子包)。
<context:component-scan base-package=“cn.test”/>

@Configuration把一个类作为一个IoC容器,它的某个方法头上如果注册了@Bean,就会作为这个Spring容器中的Bean。
@Scope注解 作用域
@Lazy(true) 表示延迟初始化
@Service用于标注业务层组件、
@Controller用于标注控制层组件(如struts中的action)
@Repository用于标注数据访问组件,即DAO组件。
@Component泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。
@Scope用于指定scope作用域的(用在类上)
@PostConstruct用于指定初始化方法(用在方法上)
@PreDestory用于指定销毁方法(用在方法上)
@DependsOn:定义Bean初始化及销毁时的顺序
@Primary:自动装配时当出现多个Bean候选者时,被注解为@Primary的Bean将作为首选者,否则将抛出异常
@Autowired 默认按类型装配,如果我们想使用按名称装配,可以结合@Qualifier注解一起使用。如下:
@Autowired @Qualifier(“personDaoBean”) 存在多个实例配合使用
@Resource默认按名称装配,当找不到与名称匹配的bean才会按类型装配。
@PostConstruct 初始化注解
@PreDestroy 摧毁注解 默认 单例 启动就加载
@Async异步方法调用[/size]

Spring AOP:在不改变源代码的情况下,可以实现功能的增强;

AOP思想:基于代理思想,对原来目标对象,创建代理对象,在不修改原对象代码情况下,通过代理对象,调用增强功能的代码,从而对原有业务方法进行增强。

AOP应用场景:
1、记录日志
2、监控方法运行时间(监控性能)
3、权限控制
4、缓存优化(第一次调用查询数据库,将查询结果放入内存对象,第二次调用,直接从内存对象返回,不需要查询数据库)
5、事务管理

实现原理:1、JDK动态代理
2、CGLib动态代理
自己实现JDK动态代理:Proxy:定义一个自己的Proxy类InvocationHandler;定义一个自己的invocationHandler类ClassLoad;自定义类加载器

交叉面很少问技术问题了,一直在问项目相关,从背景到实施到落地。问个人经历,实习经历、比赛经历、学习经历、跨专业考研经历。

交叉面聊天过程说自己写过一个高并发缓存,详细问了一下实现。

HR面只有9分钟,问个人的职业规划、为什么投阿里,现在哪家公司在沟通,会怎么选择,个人的最大优势和劣势。

【牛客网面经整理】阿里面经相关推荐

  1. 【牛客网面经整理】0805百度面经

    大家在整理面经时建议将相关问题全部整理: 1.Spring AOP,JDK代理和CGlib代理的区别,除了针对接口和类以外的不同? 答: Spring AOP是运行时织入的,那么运行时织入是怎么实现的 ...

  2. 面经八之牛客网面经整理

    目录 一.JUC多线程 二 .JVM虚拟机 三.数据库 四.Redis 五.计算机网络 六. 操作系统 七.分布式相关 八.还记得的算法题 附录: 1.单例模式(饿汉式双端检索机制valatile) ...

  3. 【牛客网面经整理】20200831小米一面

    自我介绍 答:能否胜任:性格中的闪光点: 从业时间:教育背景:工作经验:项目经验:与众不同之处:技术:性格: 算法:二叉搜索树中两个子节点的最近祖先节点.二叉树无序情况下如何寻找? 答:递归 说说ha ...

  4. [C++] 牛客网:合并两个有序的数组

    主要是体验一下牛客网里的核心代码模式到底是怎么弄的..还有C++这个东西平常用的太少了,试一试. 以外的还体验到了sort()函数的使用. 来源:牛客网 题目链接:合并两个有序的数组 知识点:数组.双 ...

  5. 字节跳动java笔试题目_牛客网--字节跳动面试题--特征提取

    牛客网--字节跳动面试题--特征提取 博客说明 文章所涉及的资料来自互联网整理和个人总结,意在于个人学习和经验汇总,如有什么地方侵权,请联系本人删除,谢谢! 来源 链接:特征提取 来源:牛客网 题目 ...

  6. 牛客网:为什么不能将实数作为 HashMap 的 key?

    欢迎关注方志朋的博客,回复"666"获面试宝典 1.起因 让我关注到这一点的起因是一道题:牛客网上的max-points-on-a-line 题目是这么描述的: Given n p ...

  7. 牛客网在线编程----算法入门篇

    标题本篇博文主要是记录下自己的在线编程情况,初次练习,有的算法还待改进,大家有需要可以去牛客网上面多练练! 有需戳–>牛客网在线编程 NC65.题目描述 大家都知道斐波那契数列,现在要求输入一个 ...

  8. 牛客网数据开发题库_练习SQL利器,牛客网SQL实战题库

    牛客网SQL实战网址:https://www.nowcoder.com/ta/sql 持续更新--记录自己在牛客网SQL的做题过程 更新进度:61题,2019-4-3,更完了 1.查找最晚入职员工的所 ...

  9. 牛客网 Wannafly挑战赛8 A.小Y和小B睡觉觉

    写了一会不想写了... A-小Y和小B睡觉觉 链接:https://www.nowcoder.com/acm/contest/57/A 来源:牛客网 时间限制:C/C++ 1秒,其他语言2秒 空间限制 ...

最新文章

  1. 公司终于决定放弃微服务传统设计模式,全面拥抱 DDD!
  2. 关于学外语,这些人人都知道的“常识”,可能是错的……
  3. xcode_6.1_gm_seed_2.dmg 下载分享
  4. VMware-workstation-6.0 安装系统前必须映射光驱盘符
  5. TextView显示颜色高亮的问题
  6. li:hover与a:hover的区别
  7. 杨辉三角c语言 用队列形式,C语言杨辉三角(循环队列).doc
  8. GBDT与LR融合现状
  9. get 和 post 区别
  10. PMP知识点速记——4.1制定项目章程
  11. 8道经典逻辑推理题(附带答案)
  12. 北京朝阳数北机房简介
  13. 批量修改文件名称方法
  14. 董明珠的“三个谜团”
  15. SVO2系列之深度滤波DepthFilter
  16. uniapp判断是不是微信浏览器
  17. html如何设置banner,css设置banner图自适应的方法
  18. 使用binlog备份恢复myqsl数据
  19. 4. DFT进阶——ATPG
  20. 「ReactNaitve」对hooks最佳实践的探索

热门文章

  1. 宽带不能上传发文件_为啥4M的宽带为啥下载速度只有300多KB?
  2. 【建议收藏】17个XML布局小技巧
  3. 关于谷歌Fuchsia,你想知道的都在这里
  4. 浅析Sublabel-Accurate Relaxation of Nonconvex Energies CVPR 2016 Best Paper Honorable Mention
  5. Android开发之集成Twitter登陆以及分享,文后有源码。
  6. 用lisp语言写一段cad提取坐标代码
  7. GCC 8.1支持C++2a的部分特性
  8. 百度语音识别开放平台SDK用法
  9. 宝付公益—书香传递温度,爱心点亮希望
  10. JavaWeb——Spring 的操作数据库的 DAO模式