Merge pull request #1 from CyC2018/master

9-22
This commit is contained in:
MyBlackHole 2019-09-22 23:57:15 +08:00 committed by GitHub
commit 3bf5a33c3f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 136 additions and 61 deletions

View File

@ -63,10 +63,12 @@ boolean 只有两个值true、false可以使用 1 bit 来存储,但是
基本类型都有对应的包装类型基本类型与其对应的包装类型之间的赋值使用自动装箱与拆箱完成
```java
Integer x = 2; // 装箱
int y = x; // 拆箱
Integer x = 2; // 装箱 调用了 Integer.valueOf(2)
int y = x; // 拆箱 调用了 X.intValue()
```
- [Autoboxing and Unboxing](https://docs.oracle.com/javase/tutorial/java/data/autoboxing.html)
## 缓存池
new Integer(123) Integer.valueOf(123) 的区别在于
@ -154,7 +156,7 @@ System.out.println(m == n); // true
## 概览
String 被声明为 final因此它不可被继承
String 被声明为 final因此它不可被继承(Integer 等包装类也不能被继承
Java 8 String 内部使用 char 数组存储数据
@ -615,7 +617,7 @@ System.out.println(InterfaceExample.x);
## super
- 访问父类的构造函数可以使用 super() 函数访问父类的构造函数从而委托父类完成一些初始化的工作
- 访问父类的构造函数可以使用 super() 函数访问父类的构造函数从而委托父类完成一些初始化的工作应该注意到子类一定会调用父类的构造函数来完成初始化工作一般是调用父类的默认构造函数如果子类需要调用父类其它构造函数那么就可以使用 super 函数
- 访问父类的成员如果子类重写了父类的某个方法可以通过使用 super 关键字来引用父类的方法实现
```java

View File

@ -56,7 +56,7 @@
- HashMap基于哈希表实现
- HashTable HashMap 类似但它是线程安全的这意味着同一时刻多个线程可以同时写入 HashTable 并且不会导致数据不一致它是遗留类不应该去使用它现在可以使用 ConcurrentHashMap 来支持线程安全并且 ConcurrentHashMap 的效率会更高因为 ConcurrentHashMap 引入了分段锁
- Hashtable HashMap 类似但它是线程安全的这意味着同一时刻多个线程可以同时写入 Hashtable 并且不会导致数据不一致它是遗留类不应该去使用它现在可以使用 ConcurrentHashMap 来支持线程安全并且 ConcurrentHashMap 的效率会更高因为 ConcurrentHashMap 引入了分段锁
- LinkedHashMap使用双向链表来维护元素的顺序顺序为插入顺序或者最近最少使用LRU顺序
@ -299,12 +299,53 @@ public synchronized E get(int index) {
}
```
### 2. ArrayList 的比较
### 2. 扩容
Vector 的构造函数可以传入 capacityIncrement 参数它的作用是在扩容时使容量 capacity 增长 capacityIncrement如果这个参数的值小于等于 0扩容时每次都令 capacity 为原来的两倍
```java
public Vector(int initialCapacity, int capacityIncrement) {
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
this.elementData = new Object[initialCapacity];
this.capacityIncrement = capacityIncrement;
}
```
```java
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
capacityIncrement : oldCapacity);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
elementData = Arrays.copyOf(elementData, newCapacity);
}
```
调用没有 capacityIncrement 的构造函数时capacityIncrement 值被设置为 0也就是说默认情况下 Vector 每次扩容时容量都会翻倍
```java
public Vector(int initialCapacity) {
this(initialCapacity, 0);
}
public Vector() {
this(10);
}
```
### 3. ArrayList 的比较
- Vector 是同步的因此开销就比 ArrayList 要大访问速度更慢最好使用 ArrayList 而不是 Vector因为同步操作完全可以由程序员自己来控制
- Vector 每次扩容请求其大小的 2 倍空间 ArrayList 1.5
- Vector 每次扩容请求其大小的 2 也可以通过构造函数设置增长的容量 ArrayList 1.5
### 3. 替代方案
### 4. 替代方案
可以使用 `Collections.synchronizedList();` 得到一个线程安全的 ArrayList
@ -650,7 +691,7 @@ static int indexFor(int h, int length) {
| capacity | table 的容量大小默认为 16需要注意的是 capacity 必须保证为 2 n 次方|
| size | 键值对数量 |
| threshold | size 的临界值 size 大于等于 threshold 就必须进行扩容操作 |
| loadFactor | 装载因子table 能够使用的比例threshold = capacity * loadFactor|
| loadFactor | 装载因子table 能够使用的比例threshold = (int)(newCapacity * loadFactor)|
```java
static final int DEFAULT_INITIAL_CAPACITY = 16;
@ -767,11 +808,11 @@ static final int tableSizeFor(int cap) {
### 8. 链表转红黑树
JDK 1.8 开始一个桶存储的链表长度大于 8 时会将链表转换为红黑树
JDK 1.8 开始一个桶存储的链表长度大于等于 8 时会将链表转换为红黑树
### 9. HashTable 的比较
### 9. Hashtable 的比较
- HashTable 使用 synchronized 来进行同步
- Hashtable 使用 synchronized 来进行同步
- HashMap 可以插入键为 null Entry
- HashMap 的迭代器是 fail-fast 迭代器
- HashMap 不能保证随着时间的推移 Map 中的元素次序是不变的

View File

@ -1329,10 +1329,10 @@ synchronized 和 ReentrantLock。
互斥同步属于一种悲观的并发策略总是认为只要不去做正确的同步措施那就肯定会出现问题无论共享数据是否真的会出现竞争它都要进行加锁这里讨论的是概念模型实际上虚拟机会优化掉很大一部分不必要的加锁用户态核心态转换维护锁计数器和检查是否有被阻塞的线程需要唤醒等操作
### 1. CAS
随着硬件指令集的发展我们可以使用基于冲突检测的乐观并发策略先进行操作如果没有其它线程争用共享数据那操作就成功了否则采取补偿措施不断地重试直到成功为止这种乐观的并发策略的许多实现都不需要将线程阻塞因此这种同步操作称为非阻塞同步
### 1. CAS
乐观锁需要操作和冲突检测这两个步骤具备原子性这里就不能再使用互斥同步来保证了只能靠硬件来完成硬件支持的原子性操作最典型的是比较并交换Compare-and-SwapCASCAS 指令需要有 3 个操作数分别是内存地址 V旧的预期值 A 和新值 B当执行操作时只有当 V 的值等于 A才将 V 的值更新为 B
### 2. AtomicInteger

View File

@ -134,7 +134,7 @@ private int rob(int[] nums, int first, int last) {
定义一个数组 dp 存储错误方式数量dp[i] 表示前 i 个信和信封的错误方式数量假设第 i 个信装到第 j 个信封里面而第 j 个信装到第 k 个信封里面根据 i k 是否相等有两种情况
- i==k交换 i k 的信后它们的信和信封在正确的位置但是其余 i-2 封信有 dp[i-2] 种错误装信的方式由于 j i-1 种取值因此共有 (i-1)\*dp[i-2] 种错误装信方式
- i==k交换 i j 的信后它们的信和信封在正确的位置但是其余 i-2 封信有 dp[i-2] 种错误装信的方式由于 j i-1 种取值因此共有 (i-1)\*dp[i-2] 种错误装信方式
- i != k交换 i j 的信后 i 个信和信封在正确的位置其余 i-1 封信有 dp[i-1] 种错误装信方式由于 j i-1 种取值因此共有 (i-1)\*dp[i-1] 种错误装信方式
综上所述错误装信数量方式数量为
@ -869,22 +869,18 @@ return -1.
```java
public int coinChange(int[] coins, int amount) {
if (amount == 0 || coins == null || coins.length == 0) {
public int change(int amount, int[] coins) {
if (coins == null) {
return 0;
}
int[] dp = new int[amount + 1];
dp[0] = 1;
for (int coin : coins) {
for (int i = coin; i <= amount; i++) { //将逆序遍历改为正序遍历
if (i == coin) {
dp[i] = 1;
} else if (dp[i] == 0 && dp[i - coin] != 0) {
dp[i] = dp[i - coin] + 1;
} else if (dp[i - coin] != 0) {
dp[i] = Math.min(dp[i], dp[i - coin] + 1);
}
for (int i = coin; i <= amount; i++) {
dp[i] += dp[i - coin];
}
}
return dp[amount] == 0 ? -1 : dp[amount];
return dp[amount];
}
```
@ -906,9 +902,6 @@ Explanation: there are four ways to make up the amount:
```java
public int change(int amount, int[] coins) {
if (amount == 0 || coins == null || coins.length == 0) {
return 0;
}
int[] dp = new int[amount + 1];
dp[0] = 1;
for (int coin : coins) {

View File

@ -242,7 +242,7 @@ do {
- 查询本身效率也可能会有所提升例如下面的例子中使用 IN() 代替连接查询可以让 MySQL 按照 ID 顺序进行查询这可能比随机的连接要更高效
```sql
SELECT * FROM tab
SELECT * FROM tag
JOIN tag_post ON tag_post.tag_id=tag.id
JOIN post ON tag_post.post_id=post.id
WHERE tag.tag='mysql';

View File

@ -316,7 +316,7 @@ SELECT ... FOR UPDATE;
MVCC 在每行记录后面都保存着两个隐藏的列用来存储两个版本号
- 创建版本号指示创建一个数据行的快照时的系统版本号
- 删除版本号如果该快照的删除版本号大于当前事务版本号表示该快照有效否则表示该快照已经被删除了
- 删除版本号如果该快照的删除版本未定义或删除版本号大于当前事务版本号表示该快照有效
## Undo 日志
@ -392,14 +392,14 @@ SELECT c FROM t WHERE c BETWEEN 10 and 20 FOR UPDATE;
## Next-Key Locks
它是 Record Locks Gap Locks 的结合不仅锁定一个记录上的索引也锁定索引之间的间隙例如一个索引包含以下值10, 11, 13, and 20那么就需要锁定以下区间
它是 Record Locks Gap Locks 的结合不仅锁定一个记录上的索引也锁定索引之间的间隙是一个前开后闭区间例如一个索引包含以下值10, 11, 13, and 20那么就需要锁定以下区间
```sql
(-, 10]
(10, 11]
(11, 13]
(13, 20]
(20, +)
(20, +supremum)
```
# 关系数据库设计理论

View File

@ -63,10 +63,12 @@ boolean 只有两个值true、false可以使用 1 bit 来存储,但是
基本类型都有对应的包装类型基本类型与其对应的包装类型之间的赋值使用自动装箱与拆箱完成
```java
Integer x = 2; // 装箱
int y = x; // 拆箱
Integer x = 2; // 装箱 调用了 Integer.valueOf(2)
int y = x; // 拆箱 调用了 X.intValue()
```
- [Autoboxing and Unboxing](https://docs.oracle.com/javase/tutorial/java/data/autoboxing.html)
## 缓存池
new Integer(123) Integer.valueOf(123) 的区别在于
@ -154,7 +156,7 @@ System.out.println(m == n); // true
## 概览
String 被声明为 final因此它不可被继承
String 被声明为 final因此它不可被继承(Integer 等包装类也不能被继承
Java 8 String 内部使用 char 数组存储数据
@ -615,7 +617,7 @@ System.out.println(InterfaceExample.x);
## super
- 访问父类的构造函数可以使用 super() 函数访问父类的构造函数从而委托父类完成一些初始化的工作
- 访问父类的构造函数可以使用 super() 函数访问父类的构造函数从而委托父类完成一些初始化的工作应该注意到子类一定会调用父类的构造函数来完成初始化工作一般是调用父类的默认构造函数如果子类需要调用父类其它构造函数那么就可以使用 super 函数
- 访问父类的成员如果子类重写了父类的某个方法可以通过使用 super 关键字来引用父类的方法实现
```java

View File

@ -56,7 +56,7 @@
- HashMap基于哈希表实现
- HashTable HashMap 类似但它是线程安全的这意味着同一时刻多个线程可以同时写入 HashTable 并且不会导致数据不一致它是遗留类不应该去使用它现在可以使用 ConcurrentHashMap 来支持线程安全并且 ConcurrentHashMap 的效率会更高因为 ConcurrentHashMap 引入了分段锁
- Hashtable HashMap 类似但它是线程安全的这意味着同一时刻多个线程可以同时写入 Hashtable 并且不会导致数据不一致它是遗留类不应该去使用它现在可以使用 ConcurrentHashMap 来支持线程安全并且 ConcurrentHashMap 的效率会更高因为 ConcurrentHashMap 引入了分段锁
- LinkedHashMap使用双向链表来维护元素的顺序顺序为插入顺序或者最近最少使用LRU顺序
@ -299,12 +299,53 @@ public synchronized E get(int index) {
}
```
### 2. ArrayList 的比较
### 2. 扩容
Vector 的构造函数可以传入 capacityIncrement 参数它的作用是在扩容时使容量 capacity 增长 capacityIncrement如果这个参数的值小于等于 0扩容时每次都令 capacity 为原来的两倍
```java
public Vector(int initialCapacity, int capacityIncrement) {
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
this.elementData = new Object[initialCapacity];
this.capacityIncrement = capacityIncrement;
}
```
```java
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
capacityIncrement : oldCapacity);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
elementData = Arrays.copyOf(elementData, newCapacity);
}
```
调用没有 capacityIncrement 的构造函数时capacityIncrement 值被设置为 0也就是说默认情况下 Vector 每次扩容时容量都会翻倍
```java
public Vector(int initialCapacity) {
this(initialCapacity, 0);
}
public Vector() {
this(10);
}
```
### 3. ArrayList 的比较
- Vector 是同步的因此开销就比 ArrayList 要大访问速度更慢最好使用 ArrayList 而不是 Vector因为同步操作完全可以由程序员自己来控制
- Vector 每次扩容请求其大小的 2 倍空间 ArrayList 1.5
- Vector 每次扩容请求其大小的 2 也可以通过构造函数设置增长的容量 ArrayList 1.5
### 3. 替代方案
### 4. 替代方案
可以使用 `Collections.synchronizedList();` 得到一个线程安全的 ArrayList
@ -650,7 +691,7 @@ static int indexFor(int h, int length) {
| capacity | table 的容量大小默认为 16需要注意的是 capacity 必须保证为 2 n 次方|
| size | 键值对数量 |
| threshold | size 的临界值 size 大于等于 threshold 就必须进行扩容操作 |
| loadFactor | 装载因子table 能够使用的比例threshold = capacity * loadFactor|
| loadFactor | 装载因子table 能够使用的比例threshold = (int)(newCapacity * loadFactor)|
```java
static final int DEFAULT_INITIAL_CAPACITY = 16;
@ -767,11 +808,11 @@ static final int tableSizeFor(int cap) {
### 8. 链表转红黑树
JDK 1.8 开始一个桶存储的链表长度大于 8 时会将链表转换为红黑树
JDK 1.8 开始一个桶存储的链表长度大于等于 8 时会将链表转换为红黑树
### 9. HashTable 的比较
### 9. Hashtable 的比较
- HashTable 使用 synchronized 来进行同步
- Hashtable 使用 synchronized 来进行同步
- HashMap 可以插入键为 null Entry
- HashMap 的迭代器是 fail-fast 迭代器
- HashMap 不能保证随着时间的推移 Map 中的元素次序是不变的

View File

@ -1329,10 +1329,10 @@ synchronized 和 ReentrantLock。
互斥同步属于一种悲观的并发策略总是认为只要不去做正确的同步措施那就肯定会出现问题无论共享数据是否真的会出现竞争它都要进行加锁这里讨论的是概念模型实际上虚拟机会优化掉很大一部分不必要的加锁用户态核心态转换维护锁计数器和检查是否有被阻塞的线程需要唤醒等操作
### 1. CAS
随着硬件指令集的发展我们可以使用基于冲突检测的乐观并发策略先进行操作如果没有其它线程争用共享数据那操作就成功了否则采取补偿措施不断地重试直到成功为止这种乐观的并发策略的许多实现都不需要将线程阻塞因此这种同步操作称为非阻塞同步
### 1. CAS
乐观锁需要操作和冲突检测这两个步骤具备原子性这里就不能再使用互斥同步来保证了只能靠硬件来完成硬件支持的原子性操作最典型的是比较并交换Compare-and-SwapCASCAS 指令需要有 3 个操作数分别是内存地址 V旧的预期值 A 和新值 B当执行操作时只有当 V 的值等于 A才将 V 的值更新为 B
### 2. AtomicInteger

View File

@ -134,7 +134,7 @@ private int rob(int[] nums, int first, int last) {
定义一个数组 dp 存储错误方式数量dp[i] 表示前 i 个信和信封的错误方式数量假设第 i 个信装到第 j 个信封里面而第 j 个信装到第 k 个信封里面根据 i k 是否相等有两种情况
- i==k交换 i k 的信后它们的信和信封在正确的位置但是其余 i-2 封信有 dp[i-2] 种错误装信的方式由于 j i-1 种取值因此共有 (i-1)\*dp[i-2] 种错误装信方式
- i==k交换 i j 的信后它们的信和信封在正确的位置但是其余 i-2 封信有 dp[i-2] 种错误装信的方式由于 j i-1 种取值因此共有 (i-1)\*dp[i-2] 种错误装信方式
- i != k交换 i j 的信后 i 个信和信封在正确的位置其余 i-1 封信有 dp[i-1] 种错误装信方式由于 j i-1 种取值因此共有 (i-1)\*dp[i-1] 种错误装信方式
综上所述错误装信数量方式数量为
@ -869,22 +869,18 @@ return -1.
```java
public int coinChange(int[] coins, int amount) {
if (amount == 0 || coins == null || coins.length == 0) {
public int change(int amount, int[] coins) {
if (coins == null) {
return 0;
}
int[] dp = new int[amount + 1];
dp[0] = 1;
for (int coin : coins) {
for (int i = coin; i <= amount; i++) { //将逆序遍历改为正序遍历
if (i == coin) {
dp[i] = 1;
} else if (dp[i] == 0 && dp[i - coin] != 0) {
dp[i] = dp[i - coin] + 1;
} else if (dp[i - coin] != 0) {
dp[i] = Math.min(dp[i], dp[i - coin] + 1);
}
for (int i = coin; i <= amount; i++) {
dp[i] += dp[i - coin];
}
}
return dp[amount] == 0 ? -1 : dp[amount];
return dp[amount];
}
```

View File

@ -242,7 +242,7 @@ do {
- 查询本身效率也可能会有所提升例如下面的例子中使用 IN() 代替连接查询可以让 MySQL 按照 ID 顺序进行查询这可能比随机的连接要更高效
```sql
SELECT * FROM tab
SELECT * FROM tag
JOIN tag_post ON tag_post.tag_id=tag.id
JOIN post ON tag_post.post_id=post.id
WHERE tag.tag='mysql';

View File

@ -316,7 +316,7 @@ SELECT ... FOR UPDATE;
MVCC 在每行记录后面都保存着两个隐藏的列用来存储两个版本号
- 创建版本号指示创建一个数据行的快照时的系统版本号
- 删除版本号如果该快照的删除版本号大于当前事务版本号表示该快照有效否则表示该快照已经被删除了
- 删除版本号如果该快照的删除版本未定义或删除版本号大于当前事务版本号表示该快照有效
## Undo 日志
@ -392,14 +392,14 @@ SELECT c FROM t WHERE c BETWEEN 10 and 20 FOR UPDATE;
## Next-Key Locks
它是 Record Locks Gap Locks 的结合不仅锁定一个记录上的索引也锁定索引之间的间隙例如一个索引包含以下值10, 11, 13, and 20那么就需要锁定以下区间
它是 Record Locks Gap Locks 的结合不仅锁定一个记录上的索引也锁定索引之间的间隙是一个前开后闭区间例如一个索引包含以下值10, 11, 13, and 20那么就需要锁定以下区间
```sql
(-, 10]
(10, 11]
(11, 13]
(13, 20]
(20, +)
(20, +supremum)
```
# 关系数据库设计理论