- 博客(69)
- 收藏
- 关注
原创 Java中如何停止一个正在运行的线程
来判断thread对象所代表的线程是否停止,但从控制台打印的结果来看,线程并未停止,这也证明了interrupted()方法的解释,测试当前线程是否已经中断。我们先来看看this.interrupted()方法的解释:测试当前线程是否已经中断,当前线程是指运行this.interrupted()方法的线程。由于stop()方法以及在JDK中被标明为“过期/作废”的方法,显然它在功能上具有缺陷,所以不建议在程序张使用stop()方法。上面的示例虽然停止了线程,但如果for语句下面还有语句,还是会继续运行的。
2024-12-03 23:02:05
2447
1
原创 Java 语法糖,你用过几个?
本文,我们介绍了 Java 语言中的一些语法糖,从上面的例子可以看出,Java 语法糖只是一些简化的语法,可以使代码更简洁易读,而本身并不增加新的功能。
2024-12-03 23:01:34
437
原创 零拷贝相关知识点(一)
是指计算机执行IO操作时,CPU不需要将数据从一个存储区域复制到另一个存储区域,从而可以减少上下文切换以及CPU的拷贝时间。,前端请求过来,服务端的任务就是:将服务端主机磁盘中的文件从已连接的socket发出去。为什么快,RocketMQ为什么快等,都涉及到零拷贝知识点。所谓的【零拷贝】,并不是真正无拷贝,而是在不会拷贝重复数据到 jvm 内存中。,包括了4次上下文切换(4次用户态和内核态的切换),4次数据拷贝(“零” :表示次数为0,它表示拷贝数据的次数为0。零拷贝是老生常谈的问题啦,大厂非常喜欢问。
2024-12-01 23:57:47
518
原创 零拷贝相关知识点(二)
是指计算机执行IO操作时,CPU不需要将数据从一个存储区域复制到另一个存储区域,从而可以减少上下文切换以及CPU的拷贝时间。,前端请求过来,服务端的任务就是:将服务端主机磁盘中的文件从已连接的socket发出去。为什么快,RocketMQ为什么快等,都涉及到零拷贝知识点。所谓的【零拷贝】,并不是真正无拷贝,而是在不会拷贝重复数据到 jvm 内存中。,包括了4次上下文切换(4次用户态和内核态的切换),4次数据拷贝(“零” :表示次数为0,它表示拷贝数据的次数为0。零拷贝是老生常谈的问题啦,大厂非常喜欢问。
2024-12-01 23:54:48
619
原创 面试题分享(一)
例如,类加载器加载了大量的类或字符串常量池耗尽时。目前的I/O多路复用都是采用的epoll模式实现,它会在通知用户进程Socket就绪的同时,把已就绪的Socket写入用户空间,不需要挨个遍历Socket来判断是否就绪,提升了性能。Redis的每个命令都是以单线程的方式执行的,整个命令的执行过程是不可中断的。在命令请求处理器中,将命令的转换使用了多线程,增加命令转换速度,在命令执行的时候,依然是单线程串行执行的。服务器端接收到请求后,进行反序列化处理,将参数恢复成函数所需的类型,并调用实际的远程函数。
2024-11-27 13:12:05
862
原创 笔试题分享(一) 2024.11.15
4-6个月单例模式:确保类只有一个实例,并提供一个全局访问方法。用于需要全局唯一实例的场景。简单工厂模式:通过一个工厂类来创建不同的对象,适用于创建逻辑复杂的对象时,通过封装创建逻辑。Docker是一种容器化技术,属于操作系统层面的虚拟化技术,将应用运行所需的所有内容比如代码、运行时环境,进行打包和隔离。微服务架构是一种将应用程序拆分成多个独立的服务的架构,每个服务通常围绕业务功能来设计拥有独立的数据库和部署方式。这些微服务通过网络通信(如HTTP、消息队列、RPC等)互相协作。
2024-11-27 13:10:29
699
原创 Dubbo八股相关知识
RPC 是指计算机 A上的进程,调用另外一台计算机B上的进程,其中 A上的调用进程被挂起,而 B上的被调用进程开始执行,当值返回给 A时,A进程继续执行。调用方可以通过使用参数将信息传送给被调用方,而后可以通过传回的结果得到信息。而这一过程,对于开发人员来说是透明的。就像后厨的例子一样,服务员把菜单传给后厨,厨师告诉备菜师和洗菜师开始工作,然后他等待他们完成工作。备菜师和洗菜师工作完之后,厨师开始炒菜。这个过程对于服务员来说其实是透明的,他不需要关心到底后厨是怎么做菜的。
2024-11-25 00:04:39
1198
原创 ES八股相关知识
在查询时,可以使用 Elasticsearch 的脚本功能(如 Painless 脚本)来处理数值计算,确保在处理过程中控制精度。·优点:灵活控制数据处理逻辑。·缺点:可能影响查询性能,增加系统复杂性。
2024-11-25 00:04:05
1194
原创 单例模式相关代码题手撕
而如果,还没有实例化的时候,多个线程进去了,也没有事,因为里面的方法有锁,只会让一个线程进入最内层方法并实例化实例。例如:线程A 只执行了 1 和 3 ,此时线程B来调用 getUniqueInstance(),发现 uniqueInstance 不为空,便获取 uniqueInstance 实例,但是其实此时的 uniqueInstance 还没有初始化。因为,即使实例已经实例化了,既后续不会再出现线程安全问题了,但是锁还在,每次还是只能拿到锁的线程进入该方法,会使线程阻塞,等待时间过长。
2024-11-18 21:13:16
700
原创 多线程相关代码题
但是注意到number=100的时候,线程B和线程C也会进入循环,当获得信号量的时候就会打印出101和102,因此要在打印之前在加个判断。然后用锁和wait来控制线程的顺序。每个线程各自打印1、2、3的倍数。方法等),当另一个线程调用其。使用Semaphore信号量机制。也就是说,每个线程打印100次。对于可能被阻塞的线程(使用。方法时,该线程将抛出一个。因此需要catch住异常。使用匿名内部类创建线程。
2024-11-18 21:12:45
126
原创 Java实习面经系列(二)— 快手
说一说你对虚拟内存的理解swap的理解(程序局部性原理)将暂时不用的程序换出到磁盘中,那如果程序在后台呢?那操作系统底层是怎么做虚拟内存和物理内存的映射的?具体说一说分页式、分段式、段页式内部碎片和外部碎片具体说一下?听你这么说,分页和分段的区别是颗粒度不一样?内核态和用户态,为什么要用这两种开销那开销具体是哪些部分?进程之间通信方式?和具体的使用场景进程和线程的区别?计算机网络四次挥手能不能优化能三次挥手?如果说一个客户端发起一个FIN请求报文,然后马上网络就断了,这个时候服务器
2024-11-11 21:05:31
333
原创 Java实习面经系列(一)
7.聚簇索引和非聚簇索引区别,b+树,跳表,二叉树比较。哈希索引和b+树的索引比较。10.MySQL语句查询过程,查询缓存什么情况下失效。4.hashmap扩容,为什么扩两倍。11.分库分表,垂直分表,水平分表。12.tcp如何保证可靠性。5.jvm新生代老年代。算法:k个一组链表翻转。
2024-11-11 21:04:45
197
原创 一些面试题总结(二)
比如A希望插入一个key-value对到HashMap中,当获取到对应的链表结点位置时,此时线程A的时间片用完了而此时线程B被调度得以执行,可能线程B占用了A计算得到的位置,插入了数值。而且,他的效率跟存活对象的个数有关。这种算法在标记阶段跟标记清除算法是一样的,但是在完成标记之后,不是直接清理垃圾内存,而是将存活对象往一端移动,然后将边界以外的所有内存直接清除。volatile修饰的变量,上方的其他写操作不能越过他的写操作排到他的下面,下方的其他读操作不能越过他的读操作排到他的上面。
2024-11-09 21:02:18
734
原创 一些面试题总结(一)
原因1、因为String类下的value数组是用final修饰的,final保证了value一旦被初始化,就不可改变其引用。2、此外,value数组的访问权限为 private,同时没有提供方法去修改这个数组。3、而且String类是用final修饰的,不可以被继承,进而避免了子类修改String。2、②节省空间–字符串常量池通过使用常量池,内容相同的字符串可以使用同一个对象,从而节省内存空间。③线程安全。
2024-11-09 21:01:30
1016
原创 Redis原理篇——Redis网络模型
我们的应用程序也好,还是内核空间也好,都是没有办法直接去物理内存的,而是通过分配一些虚拟内存映射到物理内存中,我们的内核和应用程序去访问虚拟内存的时候,就需要一个虚拟地址,这个地址是一个无符号的整数,比如一个32位的操作系统,他的带宽就是32,他的虚拟地址就是2的32次方,也就是说他寻址的范围就是0~2的32次方, 这片寻址空间对应的就是2的32个字节,就是4GB,这个4GB,会有3个GB分给用户空间,会有1GB给内核系统。不过在其database结构体中,有两个Dict:一个用来记录key-value;
2024-11-08 16:28:24
1306
原创 Redis原理篇——Redis数据结构
因为zset是是可以根据key找到score并且可以根据score进行排序的功能,所以底层采用的是跳表和哈希表,哈希表是用来进行查询,可以根据key来找到score,跳表可以根据score得分,并且能够快速的根据得分查询。当储存的所有数据都是整数的时候,set会采用整数集合Intset来存储,以节省内存。查找过程:先从第一个节点的最高级指针开始,找到下一个节点,然后下一个节点和要找的节点的得分,如果要找的得分大,就继续往后查找,如果要找的得分小,那就使用下一级的指针,类似与二分查找。
2024-11-08 16:27:18
1148
原创 计算机网络——TCP篇
TCP 和 UDP 可以使用同一个端口吗?可以的传输层中 TCP 和 UDP在内核中是两个完全独立的软件模块。可以根据协议字段来选择不同的模块来处理。TCP 连接建立TCP 三次握手过程是怎样的?SYN=1同步标志和SEQ序号=x客户端进入SYN_SENT状态SYN=1和ACK=1的标志位以及确认应答号x+1+自己的序号y服务端进入SYN_RECDACK=1的标志位和确认应答号ACK=y+1客户端和服务端都进入为什么是三次握手?不是两次、四次?
2024-11-07 16:21:50
2150
原创 计算机网络——HTTP篇
应⽤层:位于传输层之上,主要提供两个终端设备上的应⽤程序之间的通信,它定义了信息交换的格式,消息会交给下⼀层传输层来传输。传输层的主要任务就是负责向两台设备进程之间的通信提供通⽤的数据传输服务,包括TCP和UDP两种协议。⽹络层负责网络包的分组转发和路由选择,主要协议有IP协议和ARP地址解析协议等⽹络接⼝层看作是数据链路层和物理层的合体,数据链路层的作⽤是将⽹络层交下来的 IP 数据报组装成帧,MAC 寻址、差错检测,物理层的作⽤是实现相邻计算机节点之间⽐特流的透明传送。
2024-11-07 16:20:56
1351
1
原创 Docker学习—Docker的安装与使用
即把自己的java应用,定义成镜像部署到docker容器中。镜像结构是分层的,有一些已经拉取过的基础镜像就不用拉取了,节省空间。
2024-11-06 09:47:42
1075
原创 缓存与数据库一致性
一般来说,对于一个新的业务,一般会经历这几个阶段:读写流量都比较小,这个时候所有的读写操作都在主库就ok了这个时候,从库可能只是用来灾备风险分析:从数据一致性角度来说没有风险,全走主库美滋滋~单库扛不住了,这个时候就会考虑到分库分表了,通过增加数据库的方式,把单库的QPS降下来风险分析: 从数据一致性角度来说没有风险,全走主库依然美滋滋~读流量增加,主库的读QPS偏高,这个时候我们就想着把从库得利用起来,于是读写分离:写主库,读从库风险分析:读从库就意味着,读到的数据可能不是最新的,在实时性要求比较
2024-11-03 14:13:05
879
原创 Kafka相关知识点(下)
除了以上两种方式,我们还可以实现自己的分区器(Partitioner)来指定消息发送到特定的分区我们需要创建一个类实现Partitioner接口,并且重写partition()方法。在partition()方法中,我们使用了一个简单的逻辑,根据键的哈希值将消息发送到相应的分区。Partition Leader 选举Kafka 中的每个 Partition 都有一个 Leader,负责处理该 Partition 的读写请求。
2024-11-02 23:16:52
1293
原创 Kafka相关知识点(上)
使用消息队列的主要目的主要记住这几个关键词:解耦、异步、削峰填谷。在一个复杂的系统中,不同的模块或服务之间可能需要相互依赖,如果直接使用函数调用或者 API 调用的方式,会造成模块之间的耦合,当其中一个模块发生改变时,需要同时修改调用方和被调用方的代码。而使用消息队列作为中间件,不同的模块可以将消息发送到消息队列中,不需要知道具体的接收方是谁,接收方可以独立地消费消息,实现了模块之间的解耦。有些操作比较耗时,例如发送邮件、生成报表等,如果使用同步的方式处理,会阻塞主线程或者进程,导致系统的性能下降。
2024-11-02 23:15:59
1668
1
原创 Netty学习——优化与源码
第一次握手,client 发送 SYN 到 server,状态修改为 SYN_SEND,server 收到,状态改变为 SYN_REVD,并将该请求放入 sync queue 队列。其大小通过 /proc/sys/net/core/somaxconn 指定,在使用 listen 函数时,内核会根据传入的 backlog 参数与系统参数,取二者的较小值。SO_TIMEOUT 主要用在阻塞 IO,阻塞 IO 中 accept,read 等都是无限等待的,如果不希望永远阻塞,使用它调整超时时间。
2024-10-31 09:37:48
576
原创 Netty学习——Netty 进阶
三. Netty 进阶1. 粘包与半包1.1 粘包现象服务端代码public class HelloWorldServer { static final Logger log = LoggerFactory.getLogger(HelloWorldServer.class); void start() { NioEventLoopGroup boss = new NioEventLoopGroup(1); NioEventLoopGroup worke
2024-10-31 09:36:02
762
原创 Netty学习——Netty入门
二. Netty 入门1. 概述1.1 Netty 是什么?Netty is an asynchronous event-driven network application frameworkfor rapid development of maintainable high performance protocol servers & clients.Netty 是一个异步的、基于事件驱动的网络应用框架,用于快速开发可维护、高性能的网络服务器和客户端。这里的异步是指Netty采用了
2024-10-29 09:47:36
1653
原创 Netty学习——NIO基础与IO模型
导学Socket和NIO的区别Socket和NIO是Java中用于网络编程的两个不同的API,具有不同的设计理念和用途。以下是它们的主要区别:1. 定义Socket:Socket是Java中用于实现网络通信的传统API,通常被称为Java I/O(输入/输出)。它采用阻塞式I/O模型,适合于简单的网络通信。NIO (New Input/Output):NIO是Java 1.4引入的一种新的I/O库,提供了非阻塞I/O操作。它采用事件驱动和选择器(Selector)模式,适合于高并
2024-10-29 09:42:46
1352
原创 算法题总结(二十)——并查集
在第一次查询的时候,相当于是n叉树上从叶子节点到根节点的查询过程,时间复杂度是logn,但路径压缩后,后面的查询操作都是O(1),而 join 函数 和 isSame函数 里涉及的查询操作也是一样的过程。前两种入度为2的情况,一定是删除指向入度为2的节点的两条边其中的一条,如果删了一条,判断这个图是一个树,那么这条边就是答案,同时注意要从后向前遍历,因为如果两条边删哪一条都可以成为树,就删最后那一条。题目说是无向图,返回一条可以删去的边,使得结果图是一个有着N个节点的树(即:只有一个根节点)。
2024-10-22 23:45:05
773
原创 算法题总结(十九)——图论
图论DFS框架void dfs(参数) {if (终止条件) { 存放结果; return;}for (选择:本节点所连接的其他节点) { 处理节点; dfs(图,选择的节点); // 递归 回溯,撤销处理结果}}深搜三部曲确认递归函数,参数确认终止条件处理目前搜索节点出发的路径797、所有可能的路径给你一个有 n 个节点的 有向无环图(DAG),请你找出所有从节点 0 到节点 n-1 的路径并输出(不要求按特定顺序)graph[i
2024-10-22 23:43:25
1350
原创 算法题总结(十八)——单调栈
单调栈与图论单调栈解决的问题通常是一维数组,要寻找任一个元素的右边或者左边第一个比自己大或者小的元素的位置,此时我们就要想到可以用单调栈了。时间复杂度为O(n)。单调栈的本质是空间换时间,更直白来说,就是用一个栈来记录我们遍历过的元素,因为我们遍历数组的时候,我们不知道之前都遍历了哪些元素,以至于遍历一个元素找不到是不是之前遍历过一个更小的,所以我们需要用一个容器(这里用单调栈)来记录我们遍历过的元素。单调栈里存放的元素是什么?单调栈里只需要存放元素的下标i就可以了,如果需要使用对应的元素,直接T
2024-10-20 23:58:49
997
原创 算法题总结(十七)—— 动态规划(下)
那最后当然是取最小值,所以当word1[i - 1] 与 word2[j - 1]不相同的时候,递推公式:dp[i] [j] = min({dp[i - 1] [j - 1] + 2, dp[i - 1] [j] + 1, dp[i] [j - 1] + 1});因为 dp[i] [j - 1] + 1 = dp[i - 1] [j - 1] + 2,所以递推公式可简化为:dp[i] [j] = min(dp[i - 1] [j] + 1, dp[i] [j - 1] + 1);
2024-10-17 00:26:42
994
原创 算法题总结(十六)—— 动态规划(上)
凑足总额为j - coins[i]的最少个数为dp[j - coins[i]],那么只需要加上一个钱币coins[i]即dp[j - coins[i]] + 1就是dp[j](考虑coins[i])多重背包的话是从小到大的遍历!相当于二维形式的 递推公式:dp[i] [j] =dp[i-1] [j]+dp[i-1] [j-nums[i ]] , 一个使用 一个不使用。因为递推公式dp[i] += dp[i - nums[j]]的缘故,dp[0]要初始化为1,这样递归其他dp[i]的时候才会有数值基础。
2024-10-17 00:12:49
930
原创 算法题总结(十五)——贪心算法(下)
如果 ratings[i] > ratings[i + 1],此时candyVec[i](第i个小孩的糖果数量)就有两个选择了,一个是candyVec[i + 1] + 1(从右边这个加1得到的糖果数量),一个是candyVec[i](之前比较右孩子大于左孩子得到的糖果数量)。i从0开始累加rest[i],和记为curSum,一旦curSum小于零,说明[0, i]区间都不能作为起始位置,因为这个区间选择任何一个位置作为起点,到i这里都会断油,那么起始位置从i+1算起,再从0计算curSum。
2024-10-13 18:52:40
1489
原创 算法题总结(十四)——贪心算法(上)
在计算是否有峰值的时候,大家知道遍历的下标 i ,计算 prediff(nums[i] - nums[i-1]) 和 curdiff(nums[i+1] - nums[i]),如果。很容易可以发现,对于我们当前考虑的这个数,要么是作为山峰(即 nums[i] > nums[i-1]),要么是作为山谷(即 nums[i] < nums[i - 1])。实际操作上,其实连删除的操作都不用做,因为题目要求的是最长摆动子序列的长度,所以只需要统计数组的峰值数量就可以了(相当于是删除单一坡度上的节点,然后统计长度)
2024-10-13 18:51:49
1288
2
原创 算法题总结(十三)——回溯算法(下)
由于含有重复的元素,因此需要进行去重,在之前的子集问题中,是通过排序后进行去重的,但本题是要求递增的子序列,因此不能对原数组进行排序,如果排序那么数组都是自增的了。所以不能使用之前的去重逻辑。一个for循环遍历棋盘的行,一个for循环遍历棋盘的列,一行一列确定下来之后,递归遍历这个位置放9个数字的可能性!这里我明确给出了棋盘的宽度就是for循环的长度,递归的深度就是棋盘的高度,这样就可以套进回溯法的模板里了。从图中,可以看出,二维矩阵中矩阵的高就是这棵树的高度,矩阵的宽就是树形结构中每一个节点的宽度。
2024-10-08 18:41:35
847
原创 算法题总结(十二)——回溯算法(上)
因为即使排序之后,使用getsum()>target来剪枝的话,在for循环中,依然要进行到下一层的递归,而且for循环要执行结束,所以增加了复杂度!对总集合排序之后,如果下一层的sum(就是本层的 sum + candidates[i])已经大于target,就可以结束本轮for循环的遍历,因为如果不排序的话,可能还会有更小的元素。我们可以不用used数组来去重,使用index与i的关系来判断是同一个树枝还是同一层,遍历的过程中,i>index时,就是属于同一层,i==index时,是属于同一个树枝的。
2024-10-08 18:40:40
1099
原创 算法题总结(十一)——二叉树下
在递归函数有返回值的情况下:如果要搜索一条边,递归函数返回值不为空的时候,立刻返回,如果搜索整个树,直接用一个变量left、right接住返回值,这个left、right后序还有逻辑处理的需要,也就是后序遍历中处理中间节点的逻辑(也是回溯)平时我们解二叉树的题目时,已经习惯了通过节点的左右孩子判断本节点的属性,而本题我们要通过节点的父节点判断本节点的属性。如何使用切割后的后序数组来切合中序数组?后续遍历,不断把找到的p,q向上返回,如果p和q在root的两边,那个p和q最近的公共祖先就是root。
2024-10-07 20:07:08
947
原创 算法题总结(十)——二叉树上
那么可以调整最后一个节点,再将最后一个节点保存到pre里,再调整倒数第二个节点,将它的右子树设置为pre,再调整倒数第三个节点,依次类推直到调整完毕。后序遍历,先序遍历是中左右,后续遍历是左右中,那么我们只需要调整一下先序遍历的代码顺序,就变成中右左的遍历顺序,然后在反转result数组,输出的结果顺序就是左右中了。而本题的迭代法中我们使用了队列,需要注意的是这不是层序遍历,而且仅仅通过一个容器来成对的存放我们要比较的元素,,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。
2024-10-07 20:05:49
913
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人