前言
目前正在出一个查漏补缺专题
系列教程, 篇幅会较多, 喜欢的话,给个关注❤️ ~
本专题主要以Java
语言为主, 好了, 废话不多说直接开整吧~
tcp和udp区别
TCP(传输控制协议)
和UDP(用户数据报协议)
是两种常见的互联网传输协议,用于在计算机之间传输数据。它们在设计和功能上有一些显著的区别,下面是它们的详细比较:
- 可靠性:
TCP
是一种面向连接的协议,提供可靠的数据传输。它通过使用确认、重传和流量控制等机制,确保数据在发送和接收之间的可靠传递。如果发生数据丢失或损坏,TCP会自动重传丢失的数据,以确保数据的完整性和正确性。UDP
是一种无连接的协议,不提供可靠的数据传输保证。它仅将数据报发送到目标地址,不对数据传输进行确认或重传。因此,UDP在速度和效率上比TCP更快,但可能会导致数据丢失或乱序。
- 连接性:
TCP
建立一个面向连接的通信链路,首先通过三次握手建立连接,然后传输数据,最后通过四次握手关闭连接。这种连接性可以确保数据按照顺序到达目标,并且可以进行流量控制和拥塞控制。UDP
是无连接的,每个数据包都是独立传输的,不需要建立和断开连接。这使得UDP更适合于实时应用程序,如音频和视频传输,其中小的数据延迟比数据完整性更重要。
- 传输方式:
TCP
以字节流方式传输数据,将数据切割为TCP报文段,并在接收端重新组装。TCP使用序列号来跟踪和排序数据,确保按照发送顺序正确地重新组装数据。UDP
将数据分割为用户数据报(Datagram),每个用户数据报独立发送。每个数据报都有自己的标识,但它们之间没有顺序关系,接收方必须自行处理数据的顺序和完整性。
- 拥塞控制:
TCP
具有拥塞控制机制,它可以根据网络的拥塞程度调整发送数据的速率。当网络拥塞时,TCP会减少发送速率以避免丢失数据或进一步加重网络拥塞。UDP
没有内置的拥塞控制机制,它仅仅是尽力而为地将数据发送出去,不会关心网络拥塞的情况。这意味着在拥塞的网络中,UDP可能会导致数据丢失或延迟增加。
总结:TCP
适用于对数据完整性和顺序性要求较高的应用,如文件传输、网页浏览和电子邮件。UDP
适用于实时应用,如音频和视频传输,以及对实时性要求较高、可以容忍少量数据丢失的应用,如语音通信和在线游戏。选择使用TCP
还是UDP
取决于应用程序的需求,对可靠性、延迟和拥塞控制的重要性有不同的考量。
https用的是对称加密还是非对称加密
HTTPS(Hypertext Transfer Protocol Secure)
使用的是混合加密机制,包括对称加密和非对称加密。
在HTTPS通信中,对称加密用于加密和解密实际的数据传输,以保证数据的机密性和完整性。对称加密使用相同的密钥进行加密和解密操作,因此在通信双方之间需要共享密钥。对称加密算法的特点是加密和解密速度快,适合大数据量的加密和解密操作。
然而,对称加密并不能解决密钥交换的问题,因此需要非对称加密来解决这个问题。非对称加密使用公钥和私钥两个不同的密钥进行加密和解密操作。公钥可以被广泛分发给通信双方,而私钥只保留在服务器端。在HTTPS通信建立时,服务器会将自己的公钥发送给客户端,客户端使用该公钥加密一个用于对称加密的随机密钥,并发送给服务器。服务器使用自己的私钥解密该随机密钥,并与客户端共享对称密钥,用于后续的数据传输加密和解密。
通过结合对称加密和非对称加密,HTTPS实现了数据传输的机密性、完整性和身份验证。对称加密保证了数据传输的效率和速度,而非对称加密解决了密钥交换的安全性问题。这样可以确保在公开网络上进行安全的、加密的通信。
进程和线程的区别
进程
和线程
是计算机中两个重要的执行单元,它们具有以下区别:
- 定义:
进程
(Process)是正在运行的程序的实例。它是操作系统资源分配的基本单位,包含了程序的代码、数据和执行环境等。线程
(Thread)是进程中的一个独立执行路径。一个进程可以包含多个线程,每个线程都可以独立执行代码。
- 资源占用:
进程
是独立的资源分配单位,每个进程都有自己的内存空间、文件描述符、系统资源
等。进程之间的通信和资源共享需要通过特定的机制,如进程间通信(IPC
)。线程
是在进程内部创建和调度的执行单元,共享进程的资源。多个线程共享同一进程的内存空间、文件描述符和系统资源,它们之间可以通过共享内存进行通信。
- 切换开销:
- 由于
进程
拥有独立的地址空间和资源,进程间的切换开销相对较大
。切换进程需要保存和恢复进程的上下文,涉及到内存切换和资源重分配等操作。 线程
切换开销较小
,因为线程共享同一进程的资源和地址空间。线程之间的切换仅需要保存和恢复线程的上下文,开销较小。
- 并发性:
- 进程之间是独立的,每个进程有自己的执行流。多个进程可以并发执行,各自独立进行。
- 线程是进程内的执行单元,多个线程共享同一进程的资源。线程之间可以并发执行,共享进程的上下文,实现更细粒度的并发性。
- 系统支持:
进程
由操作系统进行管理和调度,操作系统分配资源、控制进程的执行,并提供进程间通信的机制。线程
由操作系统的线程库进行管理,调度和执行。线程的创建、销毁和切换由线程库提供的函数实现。
总结:
进程
是独立的资源分配单位,拥有独立的内存空间和资源,进程间切换开销较大;线程
是进程内的执行单元,共享进程的资源,线程切换开销较小。进程适合用于并行执行、独立性较强的任务,线程适合用于并发执行、共享资源的任务。
进程切换和线程切换都会干什么
进程切换和线程切换是操作系统进行任务调度
和资源分配
时的重要操作,它们的主要作用如下:
进程切换:
- 保存上下文:当操作系统决定将
CPU
的控制权从当前进程切换到另一个进程时,它首先会保存当前进程的上下文(包括程序计数器、寄存器、内存映像等)到进程控制块(PCB
)中。 - 切换内存空间:进程切换还涉及将当前进程的内存空间与下一个进程的内存空间进行切换。操作系统会更新内存管理单元和页表,将新进程的地址空间映射到物理内存上。
- 加载新进程:操作系统从就绪队列中选择一个新的进程,并加载其上下文和内存映像到对应的硬件寄存器和内存区域中。
- 恢复上下文:最后,操作系统会将保存在新进程的
PCB
中的上下文信息恢复到硬件寄存器中,使得新进程可以从上次中断的地方继续执行。
线程切换:
- 保存上下文:当操作系统决定将
CPU
的控制权从当前线程
切换到另一个线程
时,它会保存当前线程的上下文
(如程序计数器、寄存器等)到线程控制块(TCB)中。 - 切换堆栈:线程切换涉及将当前线程的堆栈切换到下一个线程的堆栈。操作系统会更新堆栈指针,使得下一个线程可以从正确的堆栈帧中恢复执行。
- 加载新线程:操作系统从就绪队列中选择一个新的线程,并加载其上下文和堆栈信息到对应的硬件寄存器和堆栈区域中。
- 恢复上下文:最后,操作系统会将保存在新线程的 TCB 中的上下文信息恢复到硬件寄存器中,使得新线程可以从上次中断的地方继续执行。
总结:
进程切换和线程切换都涉及保存和恢复上下文信息,切换内存空间或堆栈,以及加载新的任务信息。进程切换还需要处理地址空间的切换,而线程切换则主要涉及堆栈的切换。这些操作是为了实现多任务并发执行和资源分配的需要。
Java中都有哪里用到了红黑树
在Java中,红黑树(Red-Black Tree)
是一种自平衡的二叉搜索树
,它在许多核心的数据结构和算法中得到广泛应用。
TreeMap
:Java标准库中的TreeMap
类实现了基于红黑树
的有序映射(key-value
对)。它通过红黑树的特性来维护键的有序性,并提供了一系列的查找、插入和删除操作。TreeSet
:Java标准库中的TreeSet
类实现了基于红黑树
的有序集合。它使用红黑树来存储元素,并且保持集合元素的有序性。ConcurrentSkipListMap
:Java并发库中的ConcurrentSkipListMap
类是一种基于跳表(Skip List)
和红黑树
的并发有序映射。它提供了高效的并发操作,并且能够保持映射中的键有序。ConcurrentSkipListSet
:Java并发库中的ConcurrentSkipListSet
类是一种基于跳表
和红黑树
的并发有序集合。它提供了高效的并发操作,并且保持集合元素的有序性。java.util.concurrent
包中的一些并发集合和同步容器(如HashMap
、ConcurrentHashMap
、ConcurrentLinkedQueue
等)在内部的实现中也使用了红黑树
来保持数据的有序性
和高效的并发
访问。
红黑树在上述场景中被使用的原因是它能够提供高效
的查找、插入和删除操作,同时保持数据的有序性
。它的自平衡特性确保了树的高度较低,从而保证了这些操作的时间复杂度能够在对数时间范围内。这使得红黑树在需要频繁更新和查询有序数据的场景中得到了广泛的应用。
红黑树相比avl树优点在哪里
红黑树
和AVL
树都是自平衡的二叉搜索树
,它们在某些方面有相似的特性,但也存在一些区别。以下是红黑树
相比AVL
树的一些优点:
- 平衡性维护成本较低:
红黑树
通过引入颜色标记和相对较松的平衡条件来维护平衡性。相比之下,AVL
树要求严格的平衡条件,需要在每次插入或删除操作后进行更频繁的旋转调整来维持平衡。因此,红黑树的平衡性维护成本相对较低,适合于频繁进行插入和删除操作的场景。 - 更高的插入和删除性能:由于
红黑树
对平衡性的要求较松,插入和删除操作相对AVL树更快。在红黑树
中,旋转调整的次数相对较少,因此插入和删除操作的时间复杂度为O(logN)
,其中N
是树的节点数量。而AVL
树由于严格的平衡性要求,可能需要更多的旋转调整操作,导致插入和删除操作的时间复杂度更高。 - 更好的空间效率:
红黑树
通过引入额外的颜色标记来存储平衡信息,相比AVL
树,红黑树
的内存消耗较少。AVL
树需要为每个节点额外存储平衡因子(balance factor
),而红黑树
只需要存储一个比特位的颜色标记。
总体而言,红黑树
在插入和删除操作上相对AVL树
更具有优势,而AVL
树在某些场景下,如对搜索操作的频繁性能要求较高的情况下,可以选择AVL
树来获得更好的搜索性能。选择使用红黑树
还是AVL
树取决于具体的应用需求和对平衡性、插入删除性能的重要性权衡。
volatile的用处,除了保证可见性还能够干什么
除了保证可见性外,volatile还有以下作用:
禁止指令重排序
:在多线程环境中,编译器和处理器为了提高执行效率,可能会对指令进行重排序。然而,有些情况下重排序可能会导致程序的行为不符合预期。通过使用volatile关键字,可以禁止特定类型的指令重排序,保证指令按照程序的原始顺序执行。保证有序性
:在多线程环境中,volatile
关键字可以保证被标记变量的读写操作具有全局的有序性。也就是说,volatile
变量的读写操作不能被重排序到其他内存操作之前或之后,从而确保了操作的顺序性。部分替代锁的功能
:对于某些特定场景,volatile
关键字可以替代显式的锁机制,实现一些简单的同步需求。由于volatile
变量的读写操作具有原子性和可见性,可以在一些场景中使用它来保证线程安全性,避免使用锁带来的额外开销和复杂性。
需要注意的是,尽管volatile
可以提供可见性
和一定的有序性
保证,但它并不能解决所有的线程安全问题。对于复合操作(例如自增或自减操作)以及需要原子性保证的操作,仍然需要使用更强大的同步机制,如锁或原子类。
JVM中哪里会发生OOM
在Java
虚拟机(JVM)中,Out-Of-Memory(OOM)
错误可能发生在以下几个地方:
堆内存溢出(Heap Space)
:堆内存用于存储对象实例,包括新创建的对象和运行时动态分配的对象。当堆内存无法满足新对象的分配请求时,会抛出堆内存溢出异常(OutOfMemoryError
)。这通常是最常见的OOM错误类型。方法区/元空间溢出(Metaspace)
:方法区用于存储类的元数据、静态变量、常量池等信息。在较早的JVM版本中,方法区被实现为永久代(Permanent Generation
),而在较新的JVM版本中,方法区被实现为元空间(Metaspace
)。当类的元数据信息过多,或者加载的类数量过多时,方法区/元空间可能会溢出,导致OOM错误。栈溢出(Stack Overflow)
:每个线程在JVM中都有一个对应的栈,用于存储方法调用和局部变量。当递归调用层级太深,或者线程请求的栈帧超过了栈的最大深度限制,就会导致栈溢出错误(StackOverflowError
)。本地方法栈溢出(Native Method Stack)
:本地方法栈用于存储调用本地(Native
)方法的相关信息。类似于栈溢出,当本地方法的调用层级太深或者请求的栈帧超过了栈的最大深度限制时,就会发生本地方法栈溢出错误(StackOverflowError
)。直接内存溢出(Direct Memory)
:直接内存是一种不受JVM管理的内存,通常通过NIO进行操作。当程序频繁使用直接内存而没有正确释放或者申请过多的直接内存时,会导致直接内存溢出错误(OutOfMemoryError
)。
这些是常见的导致OOM
错误的地方,不同的错误类型在不同的情况下可能发生。出现OOM
错误时,一般需要根据错误信息、堆栈轨迹以及相关的监控工具进行分析和排查,以找到导致问题的具体原因,并进行相应的优化或调整。
下面写一个造成OOM
错误的方法:
public class OOMExample { public static void main(String[] args) { List<byte[]> list = new ArrayList<>(); try { while (true) { byte[] arr = new byte[1024 * 1024]; // 分配1MB的字节数组 list.add(arr); } } catch (OutOfMemoryError e) { System.out.println("OOM error occurred!"); // OOM error occurred! } } }
思考一下,这个错误发生在哪个区域呢?
上述代码中的 OutOfMemoryError(OOM)
错误将发生在堆内存
区域。通过创建大量的字节数组并将其添加到List<byte[]>
列表中,逐渐消耗堆内存的可用空间。当堆内存无法分配更多的对象实例时,JVM
将抛出 OutOfMemoryError
。
在 Java
中,堆内存用于存储对象实例,包括在运行时动态分配的对象。它是 JVM
运行时数据区域中的一部分,用于存储运行时对象的实例和数组。因此,当我们不断分配大量的对象并占用了大部分可用堆内存时,就会发生堆内存溢出(OutOfMemoryError
)错误。
如何让元空间
发生OOM
错误呢?
在Java 8及以上版本的JVM中,方法区
(或称为永久代)已经被元空间(Metaspace)
所取代。元空间是用于存储类的元数据、静态变量、常量池
等信息的区域。因此,我们可以编写一个方法来模拟元空间
的OOM
错误。
import javassist.ClassPool; public class MetaspaceOOMExample { public static void main(String[] args) { try { ClassPool classPool = ClassPool.getDefault(); int count = 0; while (true) { String className = "Class" + count++; classPool.makeClass(className).toClass(); } } catch (OutOfMemoryError e) { System.out.println("Metaspace OOM error occurred!"); } } }
上述代码使用 Javassist
库来动态
创建类并加载到元空间。在一个无限循环中,我们不断创建新的类,每个类都具有唯一的名称。随着不断创建类并加载到元空间
,元空间
的可用空间将逐渐耗尽。当元空间无法分配更多的类的元数据时,JVM
将抛出 OutOfMemoryError
,并打印"Metaspace OOM error occurred!"。
请注意,在运行此示例代码时,需要根据实际情况调整 JVM
的元空间大小限制(通过设置-XX:MaxMetaspaceSize
参数),以及足够的物理内存资源。
如何让栈
发生OOM
错误呢?
在Java
中,栈(Stack)
用于存储方法调用和局部变量等信息。栈的大小是有限的,当递归调用
层级太深或者线程请求的栈帧
超过了栈的最大深度限制时,就会发生栈溢出错误(StackOverflowError)。
以下是一个示例方法,可以用于模拟栈的OOM错误:
public class StackOOMExample { public static void recursiveMethod() { recursiveMethod(); } public static void main(String[] args) { try { recursiveMethod(); } catch (StackOverflowError e) { System.out.println("Stack Overflow error occurred!"); } } }
上述代码中的recursiveMethod
方法是一个递归方法,它会不断地调用自身。在main
方法中,我们调用recursiveMethod
方法,由于递归没有终止条件,栈的深度会不断增加,直到达到栈的最大深度限制。当栈无法再容纳更多的栈帧时,JVM 将抛出StackOverflowError
异常,并打印"Stack Overflow error occurred!"。
请注意,在运行此示例代码时,递归深度可能非常大,可能导致程序异常终止。
上述问题其实都是考察我们对JVM
的理解
JVM什么时候会将对象从新生代移动到老年代
JVM(Java虚拟机)
使用分代垃圾回收(Generational Garbage Collection)
算法来管理内存。内存被分为不同的代,主要包括新生代(Young Generation)
和老年代(Old Generation)
。
在新生代中,内存被进一步划分为Eden空间和两个Survivor
空间(通常称为From空间和To空间)。当创建对象时,它们首先被分配在Eden
空间中。垃圾回收器定期扫描新生代,将仍然活跃的对象复制到其中一个Survivor
空间中,同时清除未被引用的对象。经过多次垃圾回收后,仍然存活的对象会被移动到To
空间。
当一个对象在Survivor
空间中经历了一定数量的垃圾回收(通常是在Survivor
空间中经历了15次垃圾回收),它将被晋升
到老年代
。此外,大对象(占用大量内存的对象)
也可能会直接被分配到老年代。
老年代是用于存储长期存活
的对象和大对象
的内存区域。当老年代空间不足时,将触发一次Full GC(Full Garbage Collection)
,对整个堆内存进行垃圾回收。在Full GC
期间,所有的对象都会被扫描,未被引用的对象将被清除
,而仍然存活的对象将被保留。
总结起来,对象何时从新生代移动到老年代取决于它在新生代中存活的时间(经过多次垃圾回收)以及是否属于大对象。这种策略的目的是尽量在新生代中回收短期存活的对象,以减少Full GC
的频率和成本。
结束语
大家可以针对自己薄弱的地方进行复习, 然后多总结,形成自己的理解,不要去背~
本着把自己知道的都告诉大家,如果本文对您有所帮助,点赞+关注
鼓励一下呗~
相关文章
- 查漏补缺第一期(Redis相关)
- 查漏补缺第二期(synchronized & 锁升级)
- 查漏补缺第三期(分布式事务相关)
- 查漏补缺第四期(Mysql相关)
- 查漏补缺第五期(HashMap & ConcurrentHashMap)
- 查漏补缺第六期(京东一面)
项目源码(源码已更新 欢迎star⭐️)
往期设计模式相关文章
- 一起来学设计模式之认识设计模式
- 一起来学设计模式之单例模式
- 一起来学设计模式之工厂模式
- 一起来学设计模式之建造者模式
- 一起来学设计模式之原型模式
- 一起来学设计模式之适配器模式
- 一起来学设计模式之桥接模式
- 一起来学设计模式之组合模式
- 一起来学设计模式之装饰器模式
- 一起来学设计模式之外观模式
- 一起来学设计模式之享元模式
- 一起来学设计模式之代理模式
- 一起来学设计模式之责任链模式
- 一起来学设计模式之命令模式
- 一起来学设计模式之解释器模式
- 一起来学设计模式之迭代器模式
- 一起来学设计模式之中介者模式
- 一起来学设计模式之备忘录模式
- 一起来学设计模式之观察者模式
- 一起来学设计模式之状态模式
- 一起来学设计模式之策略模式
- 一起来学设计模式之模板方法模式
- 一起来学设计模式之访问者模式
- 一起来学设计模式之依赖注入模式
设计模式项目源码(源码已更新 欢迎star⭐️)
Kafka 专题学习
- 一起来学kafka之Kafka集群搭建
- 一起来学kafka之整合SpringBoot基本使用
- 一起来学kafka之整合SpringBoot深入使用(一)
- 一起来学kafka之整合SpringBoot深入使用(二)
- 一起来学kafka之整合SpringBoot深入使用(三)
项目源码(源码已更新 欢迎star⭐️)
ElasticSearch 专题学习
- 利用docker搭建es集群
- 一起来学ElasticSearch(一)
- 一起来学ElasticSearch(二)
- 一起来学ElasticSearch(三)
- 一起来学ElasticSearch(四)
- 一起来学ElasticSearch(五)
- 一起来学ElasticSearch(六)
- 一起来学ElasticSearch(七)
- 一起来学ElasticSearch(八)
- 一起来学ElasticSearch(九)
- 一起来学ElasticSearch(十)
- 一起来学ElasticSearch之整合SpringBoot(一)
- 一起来学ElasticSearch之整合SpringBoot(二)
- 一起来学ElasticSearch之整合SpringBoot(三)
项目源码(源码已更新 欢迎star⭐️)
往期并发编程内容推荐
- Java多线程专题之线程与进程概述
- Java多线程专题之线程类和接口入门
- Java多线程专题之进阶学习Thread(含源码分析)
- Java多线程专题之Callable、Future与FutureTask(含源码分析)
- 面试官: 有了解过线程组和线程优先级吗
- 面试官: 说一下线程的生命周期过程
- 面试官: 说一下线程间的通信
- 面试官: 说一下Java的共享内存模型
- 面试官: 有了解过指令重排吗,什么是happens-before
- 面试官: 有了解过volatile关键字吗 说说看
- 面试官: 有了解过Synchronized吗 说说看
- Java多线程专题之Lock锁的使用
- 面试官: 有了解过ReentrantLock的底层实现吗?说说看
- 面试官: 有了解过CAS和原子操作吗?说说看
- Java多线程专题之线程池的基本使用
- 面试官: 有了解过线程池的工作原理吗?说说看
- 面试官: 线程池是如何做到线程复用的?有了解过吗,说说看
- 面试官: 阻塞队列有了解过吗?说说看
- 面试官: 阻塞队列的底层实现有了解过吗? 说说看
- 面试官: 同步容器和并发容器有用过吗? 说说看
- 面试官: CopyOnWrite容器有了解过吗? 说说看
- 面试官: Semaphore在项目中有使用过吗?说说看(源码剖析)
- 面试官: Exchanger在项目中有使用过吗?说说看(源码剖析)
- 面试官: CountDownLatch有了解过吗?说说看(源码剖析)
- 面试官: CyclicBarrier有了解过吗?说说看(源码剖析)
- 面试官: Phaser有了解过吗?说说看
- 面试官: Fork/Join 有了解过吗?说说看(含源码分析)
- 面试官: Stream并行流有了解过吗?说说看
推荐 SpringBoot & SpringCloud (源码已更新 欢迎star⭐️)
- springboot-all https://github.com/qiuChengleiy/springboot-all.git
- SpringBoot系列教程合集
- 一起来学SpringCloud合集
- SpringCloud整合 Oauth2+Gateway+Jwt+Nacos 实现授权码模式的服务认证(一)
- SpringCloud整合 Oauth2+Gateway+Jwt+Nacos 实现授权码模式的服务认证(二)