diff --git a/notes/Java 并发.md b/notes/Java 并发.md index cf221ce8..15a06274 100644 --- a/notes/Java 并发.md +++ b/notes/Java 并发.md @@ -1585,7 +1585,7 @@ ThreadLocal 从理论上讲并不是用来解决多线程并发问题的,因 互斥同步的进入阻塞状态的开销都很大,应该尽量避免。在许多应用中,共享数据的锁定状态只会持续很短的一段时间。自旋锁的思想是让一个线程在请求一个共享数据的锁时执行忙循环(自旋)一段时间,如果在这段时间内能获得锁,就可以避免进入阻塞状态。 -自选锁虽然能避免进入阻塞状态从而减少开销,但是它需要进行忙循环操作占用 CPU 时间,它只适用于共享数据的锁定状态很短的场景。自旋次数的默认值是 10 次,用户可以使用虚拟机参数 -XX:PreBlockSpin 来更改。 +自选锁虽然能避免进入阻塞状态从而减少开销,但是它需要进行忙循环操作占用 CPU 时间,它只适用于共享数据的锁定状态很短的场景。 在 JDK 1.6 中引入了自适应的自旋锁。自适应意味着自旋的次数不再固定了,而是由前一次在同一个锁上的自旋次数及锁的拥有者的状态来决定。 @@ -1593,7 +1593,7 @@ ThreadLocal 从理论上讲并不是用来解决多线程并发问题的,因 锁消除是指对于被检测出不可能存在竞争的共享数据的锁进行消除。 -锁消除主要是通过逃逸分析来支持,如果堆上的共享数据不可能逃逸出去被其它线程访问到,那么就可以把它们当成私有数据对待,也就可以将它们上的锁进行消除。 +锁消除主要是通过逃逸分析来支持,如果堆上的共享数据不可能逃逸出去被其它线程访问到,那么就可以把它们当成私有数据对待,也就可以将它们的锁进行消除。 对于一些看起来没有加锁的代码,其实隐式的加了很多锁。例如下面的字符串拼接代码就隐式加了锁: @@ -1603,7 +1603,7 @@ public static String concatString(String s1, String s2, String s3) { } ``` -String 是一个不可变的类,Javac 编译器会对 String 的拼接自动优化。在 JDK 1.5 之前,会转化为 StringBuffer 对象的连续 append() 操作,在 JDK 1.5 及以后的版本中,会转化为 StringBuilder 对象的连续 append() 操作,即上面的代码可能会变成下面的样子: +String 是一个不可变的类,编译器会对 String 的拼接自动优化。在 JDK 1.5 之前,会转化为 StringBuffer 对象的连续 append() 操作: ```java public static String concatString(String s1, String s2, String s3) { @@ -1615,7 +1615,7 @@ public static String concatString(String s1, String s2, String s3) { } ``` -每个 StringBuffer.append() 方法中都有一个同步块,锁就是 sb 对象。虚拟机观察变量 sb,很快就会发现它的动态作用域被限制在 concatString() 方法内部。也就是说,sb 的所有引用永远不会“逃逸”到 concatString() 方法之外,其他线程无法访问到它。因此,虽然这里有锁,但是可以被安全地消除掉。 +每个 append() 方法中都有一个同步块。虚拟机观察变量 sb,很快就会发现它的动态作用域被限制在 concatString() 方法内部。也就是说,sb 的所有引用永远不会“逃逸”到 concatString() 方法之外,其他线程无法访问到它,因此可以进行消除。 ## 锁粗化 @@ -1647,8 +1647,6 @@ JDK 1.6 引入了偏向锁和轻量级锁,从而让锁拥有了四个状态: 偏向锁的思想是偏向于让第一个获取锁对象的线程,这个线程在之后获取该锁就不再需要进行同步操作,甚至连 CAS 操作也不再需要。 -可以使用 -XX:+UseBiasedLocking=true 开启偏向锁,不过在 JDK 1.6 中它是默认开启的。 - 当锁对象第一次被线程获得的时候,进入偏向状态,标记为 1 01。同时使用 CAS 操作将线程 ID 记录到 Mark Word 中,如果 CAS 操作成功,这个线程以后每次进入这个锁相关的同步块就不需要再进行任何同步操作。 当有另外一个线程去尝试获取这个锁对象时,偏向状态就宣告结束,此时撤销偏向(Revoke Bias)后恢复到未锁定状态或者轻量级锁状态。 diff --git a/notes/Leetcode 题解.md b/notes/Leetcode 题解.md index 8c1fd1f2..89940768 100644 --- a/notes/Leetcode 题解.md +++ b/notes/Leetcode 题解.md @@ -366,7 +366,7 @@ public int maxProfit(int[] prices) { 双指针主要用于遍历数组,两个指针指向不同的元素,从而协同完成任务。 -**有序数组的 Tow Sum** +**有序数组的 Two Sum** [Leetcode :167. Two Sum II - Input array is sorted (Easy)](https://leetcode.com/problems/two-sum-ii-input-array-is-sorted/description/) diff --git a/notes/Redis.md b/notes/Redis.md index 09246c53..2e10bb7a 100644 --- a/notes/Redis.md +++ b/notes/Redis.md @@ -6,7 +6,9 @@ * [SET](#set) * [HASH](#hash) * [ZSET](#zset) -* [三、字典](#三字典) +* [三、数据结构](#三数据结构) + * [字典](#字典) + * [跳跃表](#跳跃表) * [四、使用场景](#四使用场景) * [缓存](#缓存) * [计数器](#计数器) @@ -205,7 +207,9 @@ OK 2) "982" ``` -# 三、字典 +# 三、数据结构 + +## 字典 以下是 Redis 字典的主要数据结构,从上往下分析,一个 dict 有两个 dictht,一个 dictht 有一个 dictEntry 数组,每个 dictEntry 有 next 指针因此是一个链表结构。从上面的分析可以看出 Redis 的字典是一个基于拉链法解决冲突的哈希表结构。 @@ -309,6 +313,24 @@ int dictRehash(dict *d, int n) { } ``` +## 跳跃表 + +是有序集合的底层实现之一。 + +跳跃表是基于多指针有序链表实现的,可以看成多个有序链表。 + +