youyichannel

志于道,据于德,依于仁,游于艺!

0%

LockSupport工具类

当需要阻塞或唤醒一个线程的时候,都会使用LockSupport工具类来完成相应工作。Locksupport定义了一组的公共静态方法,这些方法提供了最基本的线程阻塞和唤醒功能,而LockSupport也成为构建同步组件的基础工具。

阅读全文 »

《MySQL是怎样运行的 —— 从跟上理解MySQL》—— 第十四章

MySQL会对于用户编写的SQL做转换,转换成某种可以比较高效执行的形式,这个过程也可以被称作查询重写

阅读全文 »

《MySQL是怎样运行的 —— 从跟上理解MySQL》—— 第十三章

一、统计数据的存储方式

InnoDB提供了两种存储统计数据的方式:

  • 永久性的统计数据:这种统计数据存储在磁盘上,也就是服务器重启之后这些统计数据还在。
  • 非永久性的统计数据:这种统计数据存储在内存中,当服务器关闭时这些这些统计数据就都被清除掉了,等到服务器重启之后,在某些适当的场景下才会重新收集这些统计数据。
阅读全文 »

队列同步器 —— AQS底层原理

队列同步器AbstractQueuedSynchronizer是用来构建锁或者其他同步组件的基础框架,它使用了一个int成员变量state表示同步状态,通过内置的FIFO队列来完成资源获取线程的排队工作。它是大部分同步需求实现的基础,也是JUC的重要组件。

阅读全文 »

Lock锁特性和常用API

Lock接口提供了与synchronized关键字类似的同步功能,只是在使用时需要显式地获取和释放锁。Lock锁缺少了隐式获取锁的便捷性,拥有锁获取和释放的可操作性、可中断地获取锁以及超时获取锁等多种特性。

使用注意:在finally块中释放锁,目的是保证在获取到锁之后,最终能够被释放。

阅读全文 »

《MySQL是怎样运行的 —— 从跟上理解MySQL》—— 第十二章

一、MySQL的查询成本

MySQL执行一个查询可以有不同的执行方案,它会选择其中成本最低,或者说代价最低的那种方案去真正的执行查询。

MySQL中一条查询语句的执行成本是由下面这两个方面组成的:

  • I/O成本:表是通过存储引擎将数据和索引都存储到磁盘上的,当想查询表中的记录时,需要先把数据或者索引加载到内存中然后再操作。这个从磁盘到内存这个加载的过程损耗的时间称之为I/O成本。
  • CPU成本:读取以及检测记录是否满足对应的搜索条件、对结果集进行排序等这些操作损耗的时间称之为CPU成本。

对于InnoDB存储引擎来说,页是磁盘和内存之间交互的基本单位,MySQL规定读取一个页面花费的成本默认是1.0,读取以及检测一条记录是否符合搜索条件的成本默认是0.21.00.2这些数字称之为成本常数

⚠️注意:不管读取记录时需不需要检测是否满足搜索条件,其成本都算是0.2。

阅读全文 »

基于类初始化的解决方案

JVM在类的初始化阶段(即在Class被加载后,且被线程使用之前),会执行类的初始化。在执行类的初始化期间,JVM会去获取一个锁,这个锁可以同步多个线程对同一个类的初始化。

阅读全文 »

基于volatile的解决方案

public class SafeDoubleCheckedLocking { // 1
private volatile static Instance instance; // 2

public static Instance getInstance() { // 3
if(instance == null) { // 4 第一次检查
synchronized(SafeDoubleCheckedLocking.class) { // 5 加锁
if(instance == null) { // 6 第二次加锁
instance = new Instance(); // 7 无问题存在了
}
} // 8
} // 9
return instance; // 10
} // 11
}

双重检查锁锁定了instance = new Instance();创建了一个对象,这一行代码可以分解为下面三行伪代码:

memory = allocate(); // 1. 分配对象的内存空间
ctorInstance(memory); // 2. 初始化对象
instance = memory; // 3. 设置instance指向刚分配的内存地址

上述的伪代码中,2和3之间因为有volatile的修饰,不会发生重排序了,就能保证拿到的对象是初始化之后的。

因为new Instance()是一个JVM指令码,对应的是new指令,volatile能够保证单个JVM指令的原子性,所以此处new Instance()相当于是volatile写,会在new Instance()前加上StoreStore屏障,后加StoreLoad屏障,其余线程就必须在StoreLoad屏障之后进行读取。实质上,new对象的三个步骤,依然可以重新排序,真正的控制是使用的外层的内存屏障。

视频地址 强推 河北王校长