Skip to content

Commit

Permalink
new update for learning note
Browse files Browse the repository at this point in the history
  • Loading branch information
rbmonster committed Jan 3, 2021
1 parent faeea1c commit f06bdbc
Show file tree
Hide file tree
Showing 14 changed files with 862 additions and 11 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
- [Java线程](https://github.com/rbmonster/learning-note/blob/master/src/main/java/com/toc/THREAD.md)
- [Java并发(虚拟机)](https://github.com/rbmonster/learning-note/blob/master/src/main/java/com/toc/CONCURRENT.md)
- [Java并发(AQS)](https://github.com/rbmonster/learning-note/blob/master/src/main/java/com/toc/CONCURRENTTOOL.md)
- [Java并发应用](https://github.com/rbmonster/learning-note/blob/master/src/main/java/com/toc/CONCURREN_APPLICATION.md)
- [Java并发应用](https://github.com/rbmonster/learning-note/blob/master/src/main/java/com/toc/CONCURRENT_APPLICATION.md)

## Spring
- [Spring 基础](https://github.com/rbmonster/learning-note/blob/master/src/main/java/com/toc/SPRING.md)
Expand Down
20 changes: 17 additions & 3 deletions src/main/java/com/learning/algorithm/ALGORITHM.md
Original file line number Diff line number Diff line change
Expand Up @@ -463,8 +463,12 @@ private int maximum_depth(TreeNode root) {
}
```
## 动态规划
- 数字翻译字符串:https://leetcode-cn.com/problems/ba-shu-zi-fan-yi-cheng-zi-fu-chuan-lcof/
-
### 并查集
## 并查集
```
class UnionFindSet {
int[] rank;
Expand Down Expand Up @@ -499,5 +503,15 @@ class UnionFindSet {
## 动态规划
- 数字翻译字符串:https://leetcode-cn.com/problems/ba-shu-zi-fan-yi-cheng-zi-fu-chuan-lcof/
## 单调栈
## 前缀树
前缀树又名字典树,单词查找树,Trie树,是一种多路树形结构,是哈希树的变种,和hash效率有一拼,是一种用于快速检索的多叉树结构。
典型应用是用于统计和排序大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计
它的优点是:最大限度地减少无谓的字符串比较,查询效率比哈希表高。
##
36 changes: 33 additions & 3 deletions src/main/java/com/learning/basic/COLLECTION.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ private void grow(int minCapacity) {
- sortedMap: 排序的Map,现阶段TreeMap是其唯一实现。
- EnumMap:要求键必须来自一个Enum。
### HashMap
#### 基本知识
基础的数据节点Node 继承Map.Entry 接口实现的key-value的数据节点
- 基本的存储的结构为Node 节点的数组
- ```
Expand Down Expand Up @@ -187,8 +188,8 @@ Map 最大大小:static final int MAXIMUM_CAPACITY = 1 << 30;
- 普通链表:循环判断链表节点是否为key相同替换情况,若均不是需要替换情况,则定位到链表尾部添加新节点。
- 红黑树:树形遍历判断是否存在,不存在添加。
##### 扩容
每次扩容的大小为 <<1,表示2的平方
#### 扩容
每次扩容的大小为 <<1,表示乘以2
1. 计算扩容新的table长度size 与threshold 的长度
2. 遍历旧table,如果节点,无哈希冲突的情况,e.hash&(newCap-1)直接定位到新的位置。
3. 出现哈希冲突的情况,由于每次扩容的大小默认为2的n次方,因此重散列的位置只会为当前位置或者当前位置+旧数组大小两个位置。
Expand All @@ -198,7 +199,7 @@ Map 最大大小:static final int MAXIMUM_CAPACITY = 1 << 30;
- 如果初始化容量大小部位2的幂次方,那么在初始化的时候,会计算threshold为大于初始化数的最近2的幂次方数,在实际使用的时候声明为table的大小。
#### HashMap红黑树查找
#### HashMap红黑树查找
红黑树建立是基于Hash的大小来建立的。这里的hashcode 为hashMap换算过的hash。hash小的为左子树, hash 大的为右子树
针对hash重复的情况:
Expand Down Expand Up @@ -269,6 +270,35 @@ static final int hash(Object key) {
}
```
#### 并发下循环链表
HashMap扩容是使用类似**头插法**的方式把旧节点转移到新的数组上。假设节点出现哈希冲突以链表的方式连接,且头节点1和节点2 扩容的位置仍然不变。
1. 当线程1与线程2新建完新数组,并且执行到上述链表节点的扩容,执行旧数组的头结点3。举个例子链表为 3->7
2. 假设线程1先执行,扩容完毕后链表变为: 7 -> 3
3. 线程2 继续运行,那么节点3 以头插法的方式接到新的数组头上,接着节点7,但是这时候节点7的next为 -> 3,
4. 当前数组节点的链表顺序为 7->3,重新进行节点3的头插,就会导致一个循环链表的现象
```
1 void transfer(Entry[] newTable) {
2 Entry[] src = table; //src引用了旧的Entry数组
3 int newCapacity = newTable.length;
4 for (int j = 0; j < src.length; j++) { //遍历旧的Entry数组
5 Entry<K,V> e = src[j]; //取得旧Entry数组的每个元素
6 if (e != null) {
7 src[j] = null;//释放旧Entry数组的对象引用(for循环后,旧的Entry数组不再引用任何对象)
8 do {
9 Entry<K,V> next = e.next;
10 int i = indexFor(e.hash, newCapacity); //!!重新计算每个元素在数组中的位置
11 e.next = newTable[i]; //标记[1]
12 newTable[i] = e; //将元素放在数组上
13 e = next; //访问下一个Entry链上的元素
14 } while (e != null);
15 }
16 }
17 }
```
[美团关于HashMap的讲解](https://tech.meituan.com/2016/06/24/java-hashmap.html)
### LinkedHashMap
基于HashMap的基础Node的节点做拓展,添加头尾指针,因此支持顺序访问。双链表加数组的实现。
```
Expand Down
271 changes: 271 additions & 0 deletions src/main/java/com/learning/basic/CONCURRENT_APPLICATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,277 @@
## 生产者与消费者模型


### synchronize

#### 基于synchronize 方法

```
public synchronized void produce() throws InterruptedException {
while (present) {
wait();
}
System.out.println(Thread.currentThread() + " Producer produce meal " + count);
count++;
this.setPresent(true);
notifyAll();
}
public synchronized void consume() throws InterruptedException {
while (!present) {
wait();
}
System.out.println(Thread.currentThread() + " consumer present meal" + count);
this.setPresent(false);
notifyAll();
}
```

#### 使用synchronize 锁对象

```
public void createByObject() throws InterruptedException {
synchronized (this) {
while (present) {
wait();
}
}
count++;
System.out.println(Thread.currentThread() + " Producer produce meal " + count);
this.setPresent(true);
synchronized (this) {
notifyAll();
}
}
public void consumerByObject() throws InterruptedException {
synchronized (this) {
while (!present) {
wait();
}
}
System.out.println(Thread.currentThread() + " consumer present meal " + count);
this.setPresent(false);
synchronized (this) {
notifyAll();
}
}
```

- 更进一步细分锁粒度,区分生产者与消费者对象。


#### 问题代码
```
public void createByObject() throws InterruptedException {
while (present) {
// 轻量级锁等待的时候,如果另个线程先获取锁,并notifyAll
// 那么可能两个线程都进入wait状态
synchronized (this) {
wait();
}
}
count++;
System.out.println(Thread.currentThread() + " Producer produce meal " + count);
this.setPresent(true);
synchronized (this) {
notifyAll();
}
}
public void consumerByObject() throws InterruptedException {
while (!present) {
// 轻量级锁等待的时候,如果另个线程先获取锁,并notifyAll
// 那么可能两个线程都进入wait状态
synchronized (this) {
wait();
}
}
System.out.println(Thread.currentThread() + " consumer present meal " + count);
this.setPresent(false);
synchronized (this) {
notifyAll();
}
}
// 正确做法 将synchronize放循环外
public void createByObject() throws InterruptedException {
synchronized (this) {
while (present) {
wait();
}
}
...
}
```


### 基于ReentrantLock 结合 condition
- 使用condition作为等待队列
```
class Consumer implements Runnable {
private ReentrantLock lock;
private Condition condition;
public Consumer(ReentrantLock lock, Condition condition) {
this.lock = lock;
this.condition = condition;
}
@Override
public void run() {
try {
while (!Thread.interrupted()) {
try {
lock.lock();
while (!ProConDemo.flag){
condition.await();
}
System.out.println( Thread.currentThread()+ " consumer shout !!!!");
ProConDemo.flag = false;
condition.signalAll();
}
finally {
lock.unlock();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class Producer implements Runnable {
private ReentrantLock lock;
private Condition condition;
public Producer(ReentrantLock lock, Condition condition) {
this.lock = lock;
this.condition = condition;
}
@Override
public void run() {
try {
while (!Thread.interrupted()) {
try {
lock.lock();
while (ProConDemo.flag){
condition.await();
}
System.out.println( Thread.currentThread()+ " producer shout~~~~");
ProConDemo.flag = true;
condition.signalAll();
}
finally {
lock.unlock();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
```

- 进阶:细分生产者队列与消费者队列

### 基于BlockingQueue
使用阻塞队列实现生产者与消费者模型
- 消费者:`queue.take();`
- 生产者:`queue.put(obj)`

## 多线程顺序输出
### 基于Synchronize锁对象
```
class Thread1 implements Runnable {
private Object obj;
public Thread1(Object obj) {
this.obj = obj;
}
@Override
public void run() {
try {
while (!Thread.interrupted()) {
synchronized (obj) {
while (!SynchronizeObject.flag) {
obj.wait();
}
System.out.println(Thread.currentThread() + " this is thread1");
SynchronizeObject.flag = false;
obj.notify();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class Thread2 implements Runnable {
private Object obj;
public Thread2(Object obj) {
this.obj = obj;
}
@Override
public void run() {
try {
while (!Thread.interrupted()) {
synchronized (obj) {
while (SynchronizeObject.flag) {
obj.wait();
}
System.out.println(Thread.currentThread() + " this is thread2~~");
SynchronizeObject.flag = true;
obj.notify();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
```


### 基于Reentrant Lock
方法1:设立一个flag,防止非公平锁抢锁输出,导致的顺序混乱问题。

方法2: 使用Reentrant Lock 公平锁
```
ReentrantLock lock = new ReentrantLock(true);
public void run() {
while (!Thread.interrupted()) {
try {
lock.lock();
System.out.println(Thread.currentThread() + " consumer shout !!!!");
} finally {
lock.unlock();
}
}
}
```


## 线程安全的类定义
1. 无状态的类:没有任何成员变量的类,如无任何方法的枚举类型。
Expand Down
Loading

0 comments on commit f06bdbc

Please sign in to comment.