Java高阶面试问答-通用基础

线程和进程区别

  1. 进程是资源分配的最小单位,线程是程序执行的最小单位
  2. 进程有自己的独立地址空间,每启动一个进程,系统就会为它分配地址空间,建立数据表来维护代码段、堆栈段和数据段。线程是共享进程的数据空间,因此CPU切换一个线程的花费远比进程要小很多,同时创建一个线程的开销也比进程要小很多
  3. 线程之间的通信更方便,同一进程下的线程共享全局变量、静态变量等数据,而进程之间的通信需要以通信的方式(IPC)进行。不过如何处理好同步与互斥是编写多线程程序的难点。

硬链接与软链接的区别

每个文件都是创建了一个指针指向inode(代表物理硬盘的一个区块),可以通过ls -i查看。
硬链接是创建另一个文件,也通过创建指针指向inode。当你删除一个文件/硬链接时,它会删除一个到底层inode的指针。当inode的所有指针都被删除时,才会真正删除文件。
软连接是另外一种类型的文件,保存的是它指向文件的全路径,访问时会替换成绝对路径

查看某个进程中的线程

ps -T -p <pid>

查看某个文件夹中每个文件夹的大小

du --max-depth=1 -h

CPU负载的含义

一段时间内CPU正在处理和等待处理的进程总数与CPU最大处理进程数的比例。对于多核CPU来说最大LOAD是最大的核心数量。
使用toptop -Hp查找到CPU占用比较大的线程,进而使用jstack来排查Java程序的问题

快速排序

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-c27SjGc2-1677425171329)(null)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WGoneqkB-1677425171347)(null)]

首先任意选取一个数据(通常选用数组的第一个数)作为关键数据,然后将所有比它小的数都放到它前面,所有比它大的数都放到它后面,这个过程称为一趟快速排序

最好情况:每次划分过程产生的区间大小都为n/2,一共需要划分log2n次,每次需要比较n-1次,O(nlog2n)
最坏情况:每次划分过程产生的两个区间分别包含n-1个元素和1个元素,一共需要划分n-1次,每次最多交换n-1次,这就是冒泡排序了,O(n2)

堆排序

  1. 根据初始数组去构造初始堆(构建一个完全二叉树,保证所有的父结点都比它的孩子结点数值大)。
  2. 每次交换第一个和最后一个元素,输出最后一个元素(最大值),然后把剩下元素重新调整为大根堆。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ziVlQu4b-1677425171285)(null)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EqJRQNy6-1677425171260)(null)]

堆排序过程的最好和最坏时间复杂度是O(nlog2n)

TOP K

如何在N个元素中寻找前K大的数?

快速排序:

  • 原理:每次快速排序中的划分过程能找到一个全部大于左边元素的一个值。如果该值的位置等于K,那么这个值和它左边的所有元素就是前K大的数;如果该值的位置小于K,那么对右边的元素继续划分排序;如果该值的位置大于K,那么对左边的元素继续划分排序
  • 问题:但空间复杂度是O(N),如果你要在很多元素中找很少几个top K的元素,或者在一个巨大的数据流里找到top K,快速排序是不合适的,堆排序更省地方

堆排序:

  • 原理:申请一个容量为K的数组,存入数组的前K个元素,创建长度为K的最小堆;从K开始循环数组的剩余元素,如果元素(a)比最小堆的根节点大,将a设置成最小堆的根节点,然后重建最小堆;循环完成后,最小堆中的所有元素就是需要找的最大的K个元素。
  • 优点:可以在N个元素中找到top K,时间复杂度是O(N log K),空间复杂的是O(K)

单例模式

  1. 懒汉(线程不安全,懒加载):如果没有实例就创建并返回,会有线程安全问题,简单加synchronized解决,但效率不高,升级版本是DCL
  2. 懒汉的升级DCL(线程安全,懒加载):加两个if是因为可能会有多个线程一起进入同步块外的if,如果在同步块内不进行二次检验的话就会生成多个实例了;instance = new Singleton()这句会有重排序的问题,用volidate解决
  3. 饿汉(线程安全,非懒加载):利用类加载器保证线程安全,但不是懒加载
  4. 饿汉升级静态内部类(线程安全,懒加载):在饿汉的基础上使用静态内部类解决非懒加载问题
  5. 枚举(线程安全,非懒加载):写法最简单,防止反序列化,但不是懒加载
    一般情况下直接使用饿汉式就好了,如果明确要求要懒加载会倾向于使用静态内部类,如果涉及到反序列化创建对象时会试着使用枚举的方式来实现单例。

状态模式

https://www.cnblogs.com/xyzq/p/11090344.html

装饰器模式

在保持原有功能接口不变的基础上动态扩展功能的模式。
Java IO包中就使用了该模式,InputStream有太多的实现类如FileInputStream,如果要在每个实现类上加上几种功能如缓冲区读写功能Buffered,则会导致出现ileInputStreamBuffered, StringInputStreamBuffered等等,如果还要加个按行读写的功能,类会更多,代码重复度也太高,你说改原来的接口也行啊,但是这样就是改变接口的内容了,现在我想做到不更改以前的功能,动态地增强原有接口。
所以使用FilterInputStream这个抽象装饰器来装饰InputStream,使得我们可以用BufferedInputStream来包装FileInputStream得到特定增强版InputStream,且增加装饰器种类也会更加灵活。

缺点:
会引入很多小类,从而增加使用复杂度,多层装饰的时候很容易导致不知道如何使用

在这里插入图片描述

策略模式

一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式。在策略模式中,我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的 context 对象。策略对象改变 context 对象的执行算法。

比如利用策略模式优化过多 if else 代码,将这些if else算法封装成一个一个的类,任意地替换

在这里插入图片描述

整体思路如下:

  1. 定义一个 InnerCommand 接口,其中有一个 process 函数交给具体的业务实现。
  2. 根据自己的业务,会有多个类实现 InnerCommand 接口;这些实现类都会注册到 Spring Bean 容器中供之后使用。
  3. 通过客户端输入命令,从 Spring Bean 容器中获取一个 InnerCommand 实例。
  4. 执行最终的 process 函数。

缺点:

  1. 策略类会增多
  2. 所有策略类都需要对外暴露。

观察者模式

当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。比如,当一个对象被修改时,则会自动通知它的依赖对象。定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。

在这里插入图片描述

观察者模式使用三个类 Subject、Observer 和 Client。Subject 对象带有绑定观察者到 Client 对象和从 Client 对象解绑观察者的方法。我们创建 Subject 类、Observer 抽象类和扩展了抽象类 Observer 的实体类。

缺点:

  1. 如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间
  2. 如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃
  3. 观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化

TCP/IP

OSI是一个理论上的七层网络通信模型,而TCP/IP则是实际运行的四层网络协议。TCP/IP包含:

  1. 网络接口层,主机必须使用某种协议与网络相连
  2. 网络层,使主机可以把分组发往任何网络,并使分组独立地传向目标。IP协议
  3. 传输层,使源端和目的端机器上的对等实体可以进行会话。TCP和UDP协议
  4. 应用层,包含所有的高层协议,FTP/TELNET/SMTP/DNS/NNTP/HTTP

HTTP

HTTP是TCP/IP协议中的【应用层】协议。它不涉及数据包传输,主要规定了客户端和服务器之间的通信格式,是互联网信息交互中最常用的协议

特点:

  1. 简单快速。只需要传【请求方法】与【资源路径】就能确定资源
  2. 灵活,传输【任意类型】的数据
  3. 无连接,一般一次连接只处理一个请求,结束后主动释放连接,但在HTTP1.1中可以使用keep-alive来复用相同的TCP连接发送多个请求
  4. 无状态,客户端向服务器发送HTTP请求之后,服务器会给我们发送数据过来,但不会记录任何信息。所以Cookie、Session产生了。

TCP

TCP是一种面向连接的、可靠的、基于字节流的TCP/IP协议中的【传输层】协议

在这里插入图片描述

建立连接:三次握手

  1. 建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SENT状态,等待服务器确认;SYN:同步序列编号(Synchronize Sequence Numbers)。
  2. 服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;
  3. 客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手。

为什么要采用三次握手,两次不行吗

避免由于网络延迟导致的创建无效连接的问题。比如客户端发出的一个连接请求没有丢失,而是长时间在某个网络节点滞留了,以至于到连接释放之后才到达服务端,如果不使用三次握手,一旦服务端发出请求连接就会建立连接,但是这个连接请求已经失效了,则会浪费服务端的资源。

关闭连接:四次挥手

  1. 当主机A的应用程序通知TCP数据已经发送完毕时,TCP向主机B发送一个带有FIN附加标记的报文段(FIN表示英文finish)。
  2. 主机B收到这个FIN报文段之后,并不立即用FIN报文段回复主机A,而是先向主机A发送一个确认序号ACK,同时通知自己相应的应用程序:对方要求关闭连接(先发送ACK的目的是为了防止在这段时间内,对方重传FIN报文段)。
  3. 主机B的应用程序告诉TCP:我要彻底的关闭连接,TCP向主机A送一个FIN报文段。
  4. 主机A收到这个FIN报文段后,向主机B发送一个ACK表示连接彻底释放。

为什么连接的时候是三次握手,关闭的时候却是四次握手

因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,“你发的FIN报文我收到了”。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。

滑动窗口协议

滑动窗口协议是传输层进行流控的一种措施,接收方通过通告发送方自己的窗口大小,从而控制发送方的发送速度,从而达到防止发送方发送速度过快而导致自己被淹没的目的。

ACK包含两个非常重要的信息:一是期望接收到的下一字节的序号n,该n代表接收方已经接收到了前n-1字节数据。二是当前的窗口大小m,如此发送方在接收到ACK包含的这两个数据后就可以计算出还可以发送多少字节的数据给对方,这就是滑动窗口控制流量的基本原理

TCP的滑动窗口是动态的,应用程序在需要(如内存不足)时,通过API通知TCP协议栈缩小TCP的接收窗口。然后TCP协议栈在下个段发送时包含新的窗口大小通知给对端,对端按通知的窗口来改变发送窗口,以此达到减缓发送速率的目的。

与UDP区别

  • TCP提供面向连接的、可靠的数据流传输,而UDP提供的是非面向连接的、不可靠的数据流传输,如QQ
  • TCP注重数据安全性,UDP数据传输快,因为不需要连接等待,少了许多操作,但是其安全性却一般
  • TCP对应的协议(FTP/SMTP/HTTP),UDP(DNS)

HTTPS

HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,要比http协议安全,可防止数据在传输过程中被窃取、改变,确保数据的完整性,它大幅增加了中间人攻击的成本。

加密过程:

  1. Hello - 握手开始于客户端发送Hello消息。包含服务端为了通过SSL连接到客户端的所有信息,包括客户端支持的各种密码套件和最大SSL版本。服务器也返回一个Hello消息,包含客户端需要的类似信息,包括到底使用哪一个加密算法和SSL版本。
  2. 证书交换 - 现在连接建立起来了,服务器必须通过SSL证书证明他的身份。SSL证书包含各种数据,包含所有者名称,相关属性(域名),证书上的公钥,数字签名和关于证书有效期的信息。客户端检查它是不是被CA验证过的且根据数字签名验证内容是否被修改过。注意服务器被允许需求一个证书去证明客户端的身份,但是这个只发生在敏感应用。
  3. 密钥交换 - 使用RSA非对称公钥加密算法(客户端生成一个对称密钥,然后用SSL证书里带的服务器公钥将该对称密钥加密。随后发送到服务端,服务端用服务器私钥解密,到此,握手阶段完成。)或者DH交换算法在客户端与服务端双方确定将要使用的密钥。这个密钥是双方都同意的一个简单,对称的密钥。这个过程是基于非对称加密方式和服务器的公钥/私钥的。
  4. 加密通信 - 在服务器和客户端加密实际信息是用到对称加密算法,用哪个算法在Hello阶段已经确定。对称加密算法是对于加密和解密都很简单的密钥。这个密钥是基于第三步在客户端与服务端已经商议好的。与需要公钥/私钥的非对称加密算法相反。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

suli77

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值