ConcurrentHashMap 为啥在initTable方法中调用thread.yield()为啥不使用Thread.sleep(0)

最近学习ConcurrentHashMap源码中发现其put时,如果当前table为空则会调用 initTable() 进行初始化。

跟踪initTable 方法发现:

initTable()方法负责初始化内部哈希表的数组。这个方法是线程安全的,它使用了一种乐观锁机制来确保只有一个线程能够初始化哈希表。让我们逐步分析这个方法的工作流程:

  1. 首先,方法通过一个while循环检查当前的table是否为null或长度为0,这表示哈希表尚未初始化。

  2. 如果table是未初始化的,它会检查sizeCtl变量的值。这个变量用于控制表的初始化和扩容操作。如果sizeCtl的值小于0,这意味着另一个线程已经在初始化或者正在扩容哈希表。

  3. 当检测到sizeCtl小于0时,当前线程调用Thread.yield()。这是因为当前线程"输掉了初始化竞赛"(lost initialization race),即它发现有另一个线程已经在进行初始化操作。在这种情况下,当前线程通过yield()让出CPU,希望给正在进行初始化的线程一个执行的机会,从而减少无谓的CPU竞争。

  4. 如果sizeCtl大于等于0,当前线程尝试使用compareAndSwapInt(CAS操作)来设置sizeCtl的值为-1,这是为了表示当前线程将负责初始化表。如果CAS操作成功,当前线程进入try块进行初始化。

  5. try块中,再次检查table是否未初始化,以防在CAS操作和这次检查之间有其他线程完成了初始化。如果table仍然未初始化,它将创建一个新的数组,并将sizeCtl设置为一个新的阈值,这个阈值是根据默认容量或者给定的初始容量计算出来的。

  6. 最后,finally块中sizeCtl被设置为新的阈值,表示初始化完成,其他线程可以开始使用哈希表了。

为啥使用Thread.yield(); 因为在JDK 1.8中,ConcurrentHashMapinitTable()方法是用于初始化内部哈希表的。在这个方法中,如果检测到有其他线程也正在尝试初始化哈希表(通过检查sizeCtl字段),当前线程会调用Thread.yield()。这是一种启发式的方法,目的是为了减少资源的浪费和竞争,让出CPU时间片给其他可能正在运行的线程,以便它们能够完成初始化工作。

Thread.yield()是一种提示调度器当前线程愿意放弃其当前的时间片,但是它并不保证会导致当前线程立即停止执行。调度器可能会忽略这个提示。在多数情况下,yield()的作用是让相同优先级的其他线程有机会执行,但是它不会导致锁等资源的释放,也不会导致线程状态的改变。

Thread.yield()相比,Thread.sleep(0)会导致当前线程暂停执行指定的时间(在这个例子中是0毫秒),并进入TIMED_WAITING状态。即使是0毫秒,sleep(0)也会请求调度器重新进行一次调度,但是它不会像yield()一样仅仅是一个提示,而是确实会导致当前线程暂停。在sleep(0)期间,其他线程可以利用CPU执行任务。

总的来说,Thread.yield()是一种对调度器的非强制性提示,让出CPU以便其他线程可以运行,但是不保证会有任何效果。而Thread.sleep(0)实际上会导致线程暂停执行,即使时间非常短,也会给其他线程执行的机会。

ConcurrentHashMapinitTable()方法中,使用Thread.yield()是为了在发现有其他线程正在进行初始化时,让当前线程暂时让出CPU,从而减少不必要的资源竞争,这是一种尝试使得初始化工作更高效的策略。

通过使用Thread.yield()ConcurrentHashMap试图减少无谓的自旋等待,这在多线程环境中可能会导致较高的CPU消耗。如果不使用yield(),那么在初始化哈希表时,其他线程将会在while循环中忙等待,这将导致CPU资源的浪费,尤其是在高负载的服务器环境中。

总之,Thread.yield()在这里是作为一种策略,用来提高多线程环境下的CPU使用效率,减少因自旋等待导致的资源浪费。

相关推荐
逊嘘10 分钟前
【Java语言】抽象类与接口
java·开发语言·jvm
morris13117 分钟前
【SpringBoot】Xss的常见攻击方式与防御手段
java·spring boot·xss·csp
monkey_meng34 分钟前
【Rust中的迭代器】
开发语言·后端·rust
余衫马37 分钟前
Rust-Trait 特征编程
开发语言·后端·rust
monkey_meng40 分钟前
【Rust中多线程同步机制】
开发语言·redis·后端·rust
七星静香41 分钟前
laravel chunkById 分块查询 使用时的问题
java·前端·laravel
Jacob程序员42 分钟前
java导出word文件(手绘)
java·开发语言·word
ZHOUPUYU43 分钟前
IntelliJ IDEA超详细下载安装教程(附安装包)
java·ide·intellij-idea
stewie61 小时前
在IDEA中使用Git
java·git
Elaine2023911 小时前
06 网络编程基础
java·网络