- 博客(35)
- 收藏
- 关注
原创 深度探讨多线程Map的底层实现(SynchronizedMap/ConcurrentHashMap)
(如果不加锁,可能在遍历链表的过程中,又有其他线程放进来一个相同的元素,但此时我已经遍历过,发现没有相同的,这样就会产生两个相同的),对该桶进行遍历,桶中的结点的 hash 值与 key 值与给定的 hash 值和 key 值相等,则根据标识选择是否进行更新操作(用给定的 value 值替换该结点的 value 值),若遍历完桶仍没有找到hash 值与 key 值和指定的 hash 值与 key 值相等的结点,则直接新生一个结点并赋值为之前最后一个结点的下一个结点。设置完毕后代表桶迁移工作已经完成,
2023-09-30 13:27:14
326
原创 深入理解HashMap底层原理(1.7与1.8比较)
HashMap的工作原理?通过hash的方法,通过put和get存储和获取对象。存储对象时,我们将K/V传给put方法时,它调用hashCode计算hash从而得到bucket位置,进一步存储,HashMap会根据当前bucket的占用情况自动调整容量(超过Load Facotr则resize为原来的2倍)。获取对象时,我们将K传给get,它调用hashCode计算hash从而得到bucket位置,并进一步调用equals()方法确定键值对。
2023-09-30 13:09:15
314
原创 Netty学习系列4—深入解析高性能和可靠性设计
Acceptor 接收到客户端TCP连接请求处理完成后(可能包括介入认证等), 将新创建的SocketChannel注册到I/O线程池(sub reactor线程池) 的某个I/O线程上, 由它负责SocketChannel的读写和辩解码工作. Acceptor线程池只用于客户端的登录、握手和安全认证, 一旦链路建立成功, 就将链路注册到后段subReactor线程池的I/O线程上, 由I/O线程负责后续的I/O操作.从架构层面看, 一个NIO线程确实可以完成起承担的职责。
2023-09-30 12:58:47
192
原创 Netty学习系列3—解析netty架构与多线程运用
Acceptor 接收到客户端TCP连接请求处理完成后(可能包括介入认证等), 将新创建的SocketChannel注册到I/O线程池(sub reactor线程池) 的某个I/O线程上, 由它负责SocketChannel的读写和辩解码工作. Acceptor线程池只用于客户端的登录、握手和安全认证, 一旦链路建立成功, 就将链路注册到后段subReactor线程池的I/O线程上, 由I/O线程负责后续的I/O操作.从架构层面看, 一个NIO线程确实可以完成起承担的职责。
2023-09-30 12:55:53
467
原创 Netty学习系列2—探索Netty客户端服务端
根据TCP三路握手过程中三个分节来分隔这两个队列. 服务器处于listen状态, 收到客户端syn分节connect时在未完成队列中创建一个新的条目, 然后用三路握手的第二个分解即服务器的syn响应客户端, 此条目在第三个分解到达前(客户端对服务器syn的ack)一直保留在未完成连接队列中, 如果三路握手完成, 该条目将从未完成丽娜姐队列半岛已完成连接队列尾部. 当进程调用accept时,从已完成队列中的头部去除一个条目给进程, 当已完成队列为空时进程将睡眠, 直到有条目在已完成连接队列中才唤醒。
2023-09-30 12:50:16
50
原创 Netty学习系列1—研究TCP粘包/拆包与私有协议栈
私有协议具有封闭性, 垄断性,排他性的特点. Netty提供的异步TCP协议栈开发一个私有协议栈, 该协议栈被命名为Netty协议栈.由两个部分组成:消息头,消息体。
2023-09-30 12:45:31
45
原创 网络编程系列2—详解套接字编程常用函数
它在调用进程(父进程)中返回一次,返回值是新派生进程(子进程)的进程ID;因此,返回值本身告诉当前进程是子进程还是父进程。我们称调用exec的进程为调用进程,新执行的程序为新程序。对于网际网协议,协议地址是32位的IPv4地址或128位的16位的TCP或UDP端口号的组合。如果父进程想跟踪它所有的子进程的ID,必须记录每次调用fork的返回值。close一个TCP套接字的默认行为是把该套接字标记为关闭,然后立即返回调用程序。内核给任何一个给定的监听套接字维护两个队列,未完成连接队列,已完成连接队列。
2023-09-30 12:35:52
49
原创 深入理解IOC和AOP
(如果是函数,需要在业务代码中调用。AOP不需要在业务代码中调用,直接在切面类中配置就可以了)面向切面编程,是一种抽象化的面向对象编程,对面向对象编程的一种补充。(一个切面对象只能跟一个实现类生成代理,然后操作代理对象编程)[GroupChat/java/aop]:业务代码和日志打印。前后都打印参数,现在想把重复的代码统一处理。主要应用场景:打印日志,事务,权限管理。IoC容器根据业务需求自动创建对象。配置自动扫包,开启自动生成代理对象。耦合度很高,灵活性太差。两种方法XML和注解。
2023-09-30 12:33:09
25
原创 网络编程系列1—探究OSI模型以及五种IO模型
任何UDP套接字都有发送缓冲区大小,不过它仅仅是可以写到该套接字的UDP数据包的大小上限,UDP是不可靠的,不必保存应用程序的数据副本,所有是无需一个真正的发送缓冲区。当某个应用进程调用write时,内核从该应用进程的缓冲区中赋值所有数据到套接字发送缓冲区。多个进程可能同时使用TCP,UDP和SCTP这三张传输层的协议中的。TCP无法仅仅通过查看目的端口号来分离外来的分节到不同的端口。如果该套接字发送缓冲区容不下所有数据,该应用进程进入睡眠。目的:可靠的实现TCP全双工连接的终止。
2023-09-30 12:27:39
32
原创 并发编程学习7—源码理解ConcurrentHashMap及其他线程安全集合类
线程安全集合类可以分为三大类:遗留的线程安全集合如 Hashtable , Vector使用 Collections 装饰的线程安全集合,如:重点介绍 java.util.concurrent.下的线程安全集合类,可以发现它们有规律,里面包含三类关键词:Blocking、CopyOnWrite、Concurrent。Blocking 大部分实现基于锁,并提供用来阻塞的方法。CopyOnWrite 之类容器修改开销相对较重。Concurrent 类型的容器。
2023-09-30 12:22:38
56
原创 并发编程学习8—AQS和ReentrantLock源码解析
全称是 AbstractQueuedSynchronizer,抽象同步队列,简称 AQS ,是Java并发包的根基,J.U.C.并发包中的锁(lock)就是基于AQS实现的。是阻塞式锁和相关的同步器工具的框架(其他工具都是它的子类)。AQS是一个接口,这个接口定义了一系列规则,而是否要设定公平锁与否由实现它的类来决定。特点:用state 属性来表示资源的状态(分独占模式和共享模式),子类需要定义如何维护这个状态,控制如何获取锁和释放锁。- getState - 获取 state 状态。
2023-09-30 12:15:01
36
原创 并发编程学习7—解密线程池
阻塞队列,为了平衡生产者和消费者(线程池)速度差异的组件。// 1) 队列满了就死等// 2) 带超时的等待// 3) 让调用者线程(main)放弃这个任务//log.debug("放弃{}", task);// 4) 让主线程抛出异常,和上面区别是让后面任务不执行了// throw new RuntimeException("任务执行失败" + task);// 5) 让调用者自己执行任务task.run();});i < 4;try {
2023-09-30 12:06:19
28
原创 并发编程学习5—深入理解Java内存模型
JMM(Java Memory Model), 从java层面定义了主存(所有线程共享的数据)、工作内存(线程私有数据)抽象概念,底层对应着 CPU 寄存器、缓存、硬件内存、CPU 指令优化等,很复杂,很难搞清,所以在java层面抽象,用关键字控制底层运作。JMM 体现在以下几个方面:原子性- 保证指令不会受到线程上下文切换的影响。可见性- 保证指令不会受 cpu 缓存的影响。有序性- 保证指令不会受 cpu 指令并行优化的影响。能保证3个,volatile只能保证后两个)
2023-09-30 11:32:43
29
原创 并发编程学习4—深入浅出线程状态
while(条件不成立) {// 干活//另一个线程当调用t.start()方法时,由 NEW --> RUNNABLE。
2023-09-29 22:45:21
31
原创 并发编程学习2—线程安全的详细分析
/ 获取静态变量i的值iconst_1// 准备常量1iadd// 自增// 将修改后的值存入静态变量i// 获取静态变量i的值iconst_1// 准备常量1isub// 自减// 将修改后的值存入静态变量i而 Java 的内存模型如下,完成静态变量的自增,自减需要在主存和工作内存中进行数据交换:是单线程以上 8 行代码是顺序执行(不会交错)没有问题,多线程就会出错。
2023-09-29 22:09:52
23
原创 并发编程学习1—解密进程与线程
程序由指令和数据组成。但指令要运行,数据要读写,就必须将指令加载到CPU,将数据加载到内存。进程就是用来加载指令,管理内存和IO的。进程可以看为一个程序的实例。一个进程里可以有多个线程。线程是一个指令流,它将以一定的顺序交给CPU执行。
2023-09-29 22:03:31
21
原创 JVM学习系列6—深入探讨线程安全与锁优化
面向过程和对象:把数据和过程分别作为独立的部分来考虑,数据代表问题空间中的客体,程序代码则用于处理这些数据,这种思维方式直接站在计算机的角度去抽象问题和解决问题,被称为面向过程的编程思想。与此相对,面向对象的编程思想则站在现实世界的角度去抽象和解决问题,它把数据和行为都看作对象的一部分,这样可以让程序员能以符合现实世界的思维方式来编写和组织程序。
2023-09-29 21:54:22
20
原创 JVM学习系列5—Java内存模型与线程剖析
正因为这个原因,本节的标题被定为“线程的实现”而不是“Java线程的实现”,在稍后介绍的实现方式中,我们也先把Java的技术背景放下,以一个通用的应用程序的角度来看看线程是如何实现。广义上来讲,一个线程只要不是内核线程,都可以认为是用户线程(User Thread,UT)的一种,因此从这个定义上看,轻量级进程也属于用户线程,但轻量级进程的实现始终是建立在内核之上的,许多操作都要进行系统调用,因此效率会受到限制,并不具备通常意义上的用户线程的优点。在同一个处理器中,重排序过的代码看起来依然是有序的。
2023-09-29 21:51:38
36
原创 JVM学习系列4—研究虚拟机字节码执行引擎
Java虚拟机是以方法作为最基本的执行单位。“栈帧”则是用来支持虚拟机进行方法调用和执行背后的数据结构。每一个方法从调用开始到执行结束,都对应着一个栈帧在虚拟机栈里的从入栈到出栈的过程。
2023-09-29 20:05:01
32
原创 JVM学习系列3—深度探讨类文件的结构与加载机制
空间层面:这些变量所用的内存应该再方法区进行分配,但方法区在8之后变成逻辑概念,所以类变量会随着Class对象一起存放在Java堆中。还有要注意的是,上面所有讲的类变量是静态变量,不包括实例变量。实例变量会在对象实例时随着对象一起分配内存在Java堆中。
2023-09-29 20:02:04
39
原创 JVM学习系列2—深度解析垃圾收集和内存分配
面向服务端应用的垃圾收集器。有“停顿时间模型”,也就是能够支持指定在一个长度为M毫秒的时间片段,消耗在垃圾收集的时间大概率不超过N秒。是一个在不同场景下关注吞吐量和延迟之间的最佳平衡的垃圾收集器。
2023-09-29 19:52:40
31
原创 JVM学习系列1—探究Java虚拟机内存区域
线程的切换是由操作系统和虚拟机共同完成的。当一个线程执行完毕后,操作系统会通知虚拟机,虚拟机再根据调度器的策略选择下一个要执行的线程,并将其程序计数器的值加载到处理器中,从而开始执行下一个线程的指令。虚拟机遇到一个字节码new指令时,首先检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用是否被加载,解析,初始化过,如果没有,就要完成这三个阶段。所有线程共享,用于存储已被虚拟机加载的类型信息,常量,静态变量或方法(可看第六章loading过程的三步),即时编译后的代码缓存。
2023-09-29 19:39:21
43
原创 Day12 滑动窗口最大值+前 K 个高频元素
给你一个整数数组nums,有一个大小为k的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的k个数字。滑动窗口每次只向右移动一位。返回滑动窗口中的最大值。示例 1:输入:nums = [1,3,-1,-3,5,3,6,7], k = 3输出:[3,3,5,5,6,7]解释:滑动窗口的位置 最大值示例 2:输入:nums = [1], k = 1输出:[1]
2023-05-22 22:17:39
68
原创 Day11 有效的括号+删除字符串中的所有相邻重复项+逆波兰表达式求值
例如:4 + 13 / 5,这就是中缀表达式,计算机从左到右去扫描的话,扫到13,还要判断13后面是什么运算符,还要比较一下优先级,然后13还和后面的5做运算,做完运算之后,还要向前回退到 4 的位置,继续做加法,你说麻不麻烦!那么将中缀表达式,转化为后缀表达式之后:[“4”, “13”, “5”, “/”, “+”] ,就不一样了,计算机可以利用栈来顺序处理,不需要考虑优先级了。第三种情况:遍历字符串匹配的过程中,栈已经为空了,没有匹配的字符了,说明右括号没有找到对应的左括号return false。
2023-05-20 20:18:37
55
1
原创 Day10 用栈实现队列+用队列实现栈
ArrayDeque是基于数组实现的双端队列,它提供了较好的随机访问性能和一致的高效性能。ArrayDeque在队列的两端(开头和末尾)都能提供高效的插入和删除操作。它可以用作Queue和Deque的实现类,但在Deque场景下,ArrayDeque的性能更好,因为它支持在两端快速插入和删除元素,如。LinkedList是基于双向链表实现的,它提供了较好的插入和删除元素的性能,尤其在队列的头部和尾部。如果需要频繁在队列两端进行插入和删除操作,使用ArrayDeque作为Deque的实现类更为合适。
2023-05-19 14:34:49
31
1
原创 Day9 实现 strStr()
题目链接](https://leetcode.cn/problems/find-the-index-of-the-first-occurrence-in-a-string/
2023-05-19 14:33:31
23
1
原创 Day8 反转字符串+反转字符串Ⅱ+替换空格+翻转字符串里的单词+左旋转字符串 - 副本
对于字符串,我们定义两个指针(也可以说是索引下标),一个从字符串前面,一个从字符串后面,两个指针同时向中间移动,并交换元素。对于字符串,我们定义两个指针(也可以说是索引下标),一个从字符串前面,一个从字符串后面,两个指针同时向中间移动,并交换元素。遍历字符串的过程中,只要让 i += (2 * k),i 每次移动 2 * k 就可以了,然后判断是否需要有反转的区间。因为要找的也就是每2 * k 区间的起点,这样写,程序会高效很多。如何跳过中间连续的空格。如何修剪掉两端空格;如何把单词反转过来;
2023-05-17 14:32:25
44
1
原创 Day4 两两交换链表中的节点+删除链表的倒数第N个节点+链表相交+环形链表Ⅱ
其实这种情况和n为1的时候 效果是一样的,一样可以通过这个方法找到 环形的入口节点,只不过,index1 指针在环里 多转了(n-1)圈,然后再遇到index2,相遇点依然是环形的入口节点。[[19.删除链表的倒数第N个节点1.png]]!fast 走两个节点,slow走一个节点,有环的话,一定会在环内相遇呢,而不是永远的错开呢。先拿n为1的情况来举例,意味着fast指针在环形里转了一圈之后,就遇到了 slow指针了。,n为fast指针在环内走了n圈才遇到slow指针, (y+z)为 一圈内节点的个数A。
2023-05-14 16:15:12
56
原创 Day2 有序数组的平方+长度最小的子数组+螺旋矩阵II
所以数组平方的最大值就在数组的两端,不是最左边就是最右边,不可能是中间。第一种想法,2层循环:第一层for循环控制区间的起始位置,第二层while循环控制区间的终止位置。这些集合里面的所有的长度,再取一个最小的。分析:如果第一层循环是循环的窗口的起点位置,终止位置需要一个一个往后移,去搜集所有。,我们再去移动起始位置,这样就实现了动态调整起始位置,来去收集不同长度区间里面的和。的话,说明这是符合条件的一个集合,我们收集它的长度之后,起点位置就可以向后移动了。,从而得出我们要想的结果。里面的循环条件,每次。
2023-05-11 20:07:53
39
1
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人