自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+
  • 博客(22)
  • 收藏
  • 关注

原创 Java中的阻塞队列--以LinkedBlockingQueue为例

顾名思义,就是一种在对队列进行出队或者入队操作的时候会阻塞的队列。下面使用JDK17中的LinkedBlockingQuece进行简单的介绍。

2025-01-21 14:33:11 384

原创 赛博考古(4) ThreadLocal中的Hash函数与三间隙定理

ThreadLocal存储数据并不是直接存储数据,而是自己作为key将value存储到ThreadLocal自带的ThreadLocalMap中。ThreadLocalMap中负责存储键值对的数据结构为一维数组。这篇文章就来分析一下,ThreadLocalMap是如何进行hash取值,并如何解决碰撞问题。从下面代码可以看出键值对在数组中的位置由当前数组的大小len以及作为key的ThreadLocal对象的threadLocalHashCode来确定。

2025-01-07 13:14:34 1126

原创 ThreadLocal源码分析

ThreadLocal 为线程提供一个线程安全的存储空间,只有该线程能够访问。实际上ThreadLocal其中并不存储数据,而是作为key,存储到Thread自带的ThreadLocal Map中。ThreadLocal的使用方法非常简单,在一个线程中声明出一个ThreadLocal变量便可以使用。下面的源码展示出ThreadLocal的基本使用ThreadLocal一共只暴露出了,五个public方法,我们首先研究一下这五个方法的作用。

2025-01-07 13:12:19 588

原创 从AQS学习CAS操作

下面分析一下,是如何实现折现线程安全的操作,首先需要用到Unsafe类,从名字就能看出来这是个 “不安全”的类,因为它提供了对底层内存的直接操作。如果操作时的值等于传入的expect值那么原子性更新为update的值,返回true;然后将对象实例,偏移量,以及expect值,和更新的值传入进到 Unsafe类提供的compareAndSetInt()中。Unsafe便会调用native方法去原子性更新STATE指向的内存的值。首先获取一个 Unsafe实例,然后获取类中字段的偏移量。

2024-12-12 09:06:58 246

原创 并发编程基础:监视器模式

Java 监视器模式仅仅是一种编写代码的预定,对于任何一种锁对象,只要自始至终都是用该锁对象,都可以用来保护对象的状态。下面是一个私有锁保护状态的例子。在某些情况下,程序需要一种更复杂的同步策略,Java监视器模式的主要优势就在于它的简单性。私有锁优点:私有锁可以将锁封装起来,无法让客户代码得到锁,但是可以通过公有方法访问锁。如果需要验证某个共有访问的锁在程序中是否被正确执行,需要检查整个程序,而不是单个的类。遵循监视器模式的对象会把对象的所有可变状态封装起来,并由对象自己的内置锁来保护。

2024-12-09 23:50:44 170

原创 从底层了解JAVA多线程:MESI缓存一致性协议详解

状态,表示该数据块被当前处理器缓存独占,那么针对这个数据块的写将不会产生让其他缓存失效的广播信号,而是直接将状态变为 M。当该数据块被其他缓存请求读的时候,表示数据块会被拷贝到另外的缓存,当前缓存中并非唯一拷贝了,状态则会转变为。发现MSI协议存在一个问题:在每次处理器想要读取读取一个数据块的时候,数据总会变成 Shared状态,即使没有其他的拷贝在其他处理器的缓存中。当该数据块被其他缓存请求写的时候,那么该数据块在被传输到其他拷贝后,该缓存的数据块失效,标记为 Shared。

2024-12-09 23:45:09 447

原创 JMM究竟干了什么?

对于编译器,JMM的编译器重排序会禁止特定类型的编译器重排序,对于处理器重排序,JMM的处理器会要求java编译器在生成指令序列的时候,插入特定类型的内存屏障指令。单线程的程序遵循as-if-serial语义,不管怎么重排序,单线程程序的执行结果不会改变。编译器和处理器不会对存在数据依赖关系的操作做重排序。as-if-serial语义把单线程程序保护起来,使得单线程程序员无需重排序会干扰他们,也无需担心内存可见性问题。JMM保证程序在正确同步时,程序执行结果和顺序一致性模型中执行结果相同。

2024-12-06 11:07:24 217

原创 对象的发布与逸出

发布(Publish)一个对象指,使得对象在当前作用域之外的代码中使用。当某个不该发布的对象被发布的时候被称为逸出(Escape)。比如将一个对象保存为static变量,让其他线程能够访问,或者通过一个public的方法去返回一个对象的引用。下面用static变量来举例。

2024-12-06 11:02:27 176

原创 赛博考古(3)MCS锁原论文伪代码详解

假设当PROCESS获取锁之后,PROCESS2也来获取锁,那么就会使得LOCK指向新入队的PROCESS2节点,然后判断前继为PROCESS节点自己并不是第一个节点,那么开始自旋,自旋监控的是自身的locked字段。在MCS锁提出之前,普通的自旋锁忙等的时候是需要消耗cpu并且众多线程去访问同一个共享变量,这样做会导致缓存中的共享变量的拷贝频繁失效,也就是文中提到的大型内存多处理器中可扩展性和可接受性能的主要障碍。类似的,该锁分为三个部分,锁定义以及获取锁和释放锁两个操作。在这片论文中,作者们提到。

2024-12-05 19:40:18 384

原创 赛博考古(2),CLH锁原文伪代码讲解

它是一种基于队列的自旋锁,线程通过自旋等待自己的前驱线程释放锁,从而实现了线程的有序访问。将节点的状态变为 GRANTED,通知下一个正在自旋节点等待的线程。两个操作,分配一个新的Request对象给L.tail并且把这个Request对象的状态变为GRANTED,表示新建出来的锁的状态是空闲的。CLH队列的讲解就此结束,可以看到论文中原始的CLH队列和AQS中使用的CLH变体队列还是有很大差异的。然后,定义了Process的结构,包含两个字段,分别为指向监视字段的watch,指向自己的 myreq。

2024-12-05 17:48:54 303

原创 AQS 核心源码 acquire() 函数详解

null 的时候已经是false,直接进入part2。但是此时只是创建node,AQS会让线程再次自旋一次去尝试获取资源,因为我们的node没有入队,那么经过part1的时候失败再去part2,假设part2成功请求到了资源,那么结束执行,如果没有请求成功,那么经过一次自旋后,我们的线程依旧没有争取到资源,那么此时就要执行入队操作。如果解除阻塞后消耗尽了自旋次数还没有成功获取资源,那么就再次进入阻塞状态,同时会更新下次解除阻塞后允许的自旋次数,阻塞次数越多,允许自旋的次数越多,分别为1,3,7,15…

2024-12-05 15:20:25 1022

原创 赛博考古(1),JAVA中的抽象队列同步器(AQS)

抽象队列同步器按照JDK17中的注释,主要目的是为开发者提供一个能够实现阻塞锁以及相关同步器的框架,这个框架依赖一个先进先出的等待队列。开发者为以及 JCP JSR-166的成员,经常阅读java.util.concurrent包源码的朋友对这个名字应该并不陌生。我们现在所熟知的JAVA并发开发工具类以及各种原子类都是由**Doug Lea以及JSR-166团队 **开发出的第一个版本,另外 **Doug Lea **也参与JSR-133 JAVA内存模型的改进工作。这些工作在JAVA1.5中正式发布。

2024-12-02 23:50:56 1297 1

原创 JAVA中ReentrantLock的公平锁与非公平锁

可重入互斥独占锁(a reentrant mutual exclusion)默认创建的是非公平锁使用另一个构造函数能够指定公平锁和非公平锁从具体的实现上来看,公平锁与非公平锁同样是继承的一个Sync类,主要有两个方法不同。非公平锁使用CAS操作对AQS中的state进行compareAndSetState(0, 1)操作,具体AQS在干什么喝CAS操作是什么可以参考其他文章,比较复杂这里不在讲解。简单来说,在线程获取对象锁的时候,如果对象锁被其他对象获取,那么该线程就会进入一个同步队列进行排队。

2024-11-26 19:51:04 355

原创 从底层了解JAVA多线程:MSI缓存一致性协议详解

想要读懂本文需要对计算机底层尤其是CPU主存以及缓存有一定的了解。本文目的在于帮助JAVA开发者了解多线程的底层究竟在发生什么,在多处理器计算机中是如何来处理程序的。

2024-09-28 22:30:13 1563

原创 JAVA多线程基础:方法加锁与代码块加锁的时间消耗差异

这是因为代码块加锁只锁住必要的部分,降低了锁的持有时间,从而减少了线程之间的等待和锁竞争。分别运行getV1() 和 getV2()的代码 5次,观察实验结果。只锁住了代码块,线程能够更快地获取到锁,执行效率更高。锁住了整个方法,导致线程在执行。时必须等待其他线程释放锁。

2024-09-19 16:04:28 252

原创 JAVA多线程基础:单例模式与双重检查锁

因为在第一次判断出instance为null的时候,可能有多个进程进入第一个判断为空的代码块。当在等待得到锁的线程需要再判断依次instance是否为空,因为可能已经有线程创建了instance。值得注意的是,重排序可能发生在编译在字节码阶段,jvm生成native code阶段,以及硬件执行阶段。这是因为两个线程可能同时进入这段代码,当判断instance为空的时候,都会去尝试新建一个实例。选择在方法块上加锁,值得注意的是这里出现了两次判断 instance是否为空因此该方法被命名为双重锁。

2024-09-18 17:21:30 1957

原创 JAVA 内存模型论文解读(1)

在学习JAVA多线程时,发现多线程内容是建立在JAVA内存模型上的。JAVA内存模型的上次主要更改在JAVA 5版本。

2024-09-18 15:35:17 208

原创 HashMap:由浅入深学习HashMap源码(1)

JDK 17的HashMap 提供了30个 public 方法。Hash table 实现了 map接口。HashMap 和 Hash table大致相同,但是他是线程不安全的并且允许 null 值以及 null key。Hash Map能够在常量的时间内实现get 和 put操作。

2024-09-16 18:27:23 427

原创 JAVA 多线程基础:JAVA中double 和 long非原子读写问题

对于double以及long两种基本数据类型,所占位数为64位。而JVM却有32bit与64bit两种,也就是说在32bit JVM中不能将double 与 long类型的数据在一条指令中进行处理。为了处理64bit的数据,32bit的JVM会将一次对64bit的数据操作变为两次对32bit的操作。

2024-09-16 16:29:59 1964

原创 JAVA多线程基础:同步代码块基本操作与可重入机制(Synchronized Block)

java同步代码块机制

2024-09-13 16:41:59 506

原创 JAVA多线程基础:竞态条件

竞态条件会使得结果变得不可靠。当某个计算的正确性取决于多个线程的交替执行时序时,就会发生竞态条件。最常见的竞态条件为,“先检查后执行(Check-Then-Act )”即通过一个可能失效的观测结果决定下一步动作。

2024-09-03 16:21:37 370 1

原创 Java网络聊天室代码实现,资源链接整合

2021/9/14上学期学习了java,期末时做了一个多人在线聊天室。抽时间来总结一下开发学习历程。类似的文章在csdn上已经有了很多,自己最终做出的作品也不是很出色,刚好利用这个机会改进一下。在总结时我会把每个问题参考的博客链接放在下面。暑假的时间由于项目需求,接触了点区块链和IPFS里面的知识,尝试下能不能将两个结合起来,做一个区块链多人在线聊天室。今天算是开了一个坑,希望能填满。1.测试链接​ 既然要做一个网络多人的聊天室,那就不能仅限于在本地运行程序。聊天室应该是基于C/S模式的应用程序,

2021-09-15 15:30:43 386

空空如也

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除