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 Apr 28, 2021
1 parent c3e7717 commit 23ebd1d
Show file tree
Hide file tree
Showing 8 changed files with 308 additions and 102 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,9 @@
## 其他
### 记录平常学习java 的一些知识点
- [设计模式(head first)](https://github.com/rbmonster/learning-note/blob/master/src/main/java/com/toc/CODEDESIGN_BOOK.md)
- [JVM基础(周志明)](https://github.com/rbmonster/learning-note/tree/master/src/main/java/com/toc/JVM_BOOK.md)
- [Redis基础(基于Redis的设计与实现)](https://github.com/rbmonster/learning-note/tree/master/src/main/java/com/toc/REDIS_BOOK.md)
- [MySql45讲](https://github.com/rbmonster/learningA-note/tree/master/src/main/java/com/toc/MYSQL_BOOK.md)
- [深入理解Java虚拟机(周志明)](https://github.com/rbmonster/learning-note/tree/master/src/main/java/com/toc/JVM_BOOK.md)
- [Redis-基于Redis的设计与实现](https://github.com/rbmonster/learning-note/tree/master/src/main/java/com/toc/REDIS_BOOK.md)
- [MySql 45讲-丁奇](https://github.com/rbmonster/learning-note/tree/master/src/main/java/com/toc/MYSQL_BOOK.md)
- [java集合类(Java编程思想)](https://github.com/rbmonster/learning-note/tree/master/src/main/java/com/toc/COLLECTION_BOOK.md)
- [java并发(Java编程思想)](https://github.com/rbmonster/learning-note/tree/master/src/main/java/com/toc/CONCURRENT_BOOK.md)

Expand Down
14 changes: 7 additions & 7 deletions src/main/java/com/learning/collection/COLLECTION_BOOK.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
- 记录一下在Thinking in java 里面的一些方法
## 集合容器
### list相关
# 集合容器
## list相关
- CopyOnWriteArrayList:使用了读写分离的思想,在写数据的时候上ReentrantLock锁并新建一个数组,读数据仍从旧数组中读取,而新数据在新增或删除完成之后直接替换旧数组。虽然线程安全,对于频繁写数据的场景效率很低。
- ListIterator: 更强大的Iterator的子类,用于各种List类的访问,并支持双向移动。
- LinkedList:
Expand All @@ -9,7 +9,7 @@
- removeFirst() 和 remove() 类似,移除并返回列表的头,只是列表为空抛出NoSuchElementException。
- poll() 同样移除并返回列表头,只是列表为空返回Null
- Stack:pop()、push()、 peek()方法,其中peek()返回栈顶元素,而不将其移除。
### Set相关:
## Set相关:
- TreeSet:将元素存储在红-黑树的数据结构中,而HashSet使用的是散列函数。
- LinkedHashSet:具有HashSet的查询速度,且内部使用链表维护元素的顺序。
- HashSet: 存入的元素必须实现hashSet()方法。
Expand All @@ -22,7 +22,7 @@
- poll() 在队列为空时返回null,而remove()会抛出NoSuchElementException()。
- PriorityQueue:优先级队列弹出的元素具有最高的优先级。

### Map 相关:
## Map 相关:
- HashMap: 给予散列表实现。可以通过构造器设置容量和负载因子,以调整容器的性能
- LinkedHashMap:类似HashMap,但是迭代访问时,取得“键值对”的顺序是按其插入对的顺序,或者是最近最少使用(LRU)的次序。
- 在构造器可以指定参数为new LinkedHashMap<>(initialCapacity, loadFactor, true),initialCapacity为初始容量,loadFactor为加载因子,true表示使用LRU访问。
Expand All @@ -42,20 +42,20 @@
- 再散列:达到该负载因子水平时,容器将自动增加容量,使容器的容量大致加倍,并重新分布到新的桶位集中(再散列)。
- HashMap中的默认负载因子为0.75,这个因子在时间和空间代价之间达到了平衡。

### 快速报错机制
## 快速报错机制
- 定义探查容器上的任何除了你的进程所进行的操作之外的所有变化,一旦发现立即抛出ConCurrentModificationException的异常。

### 散列
- 散列的价值在于速度,散列是的查询得以快速进行。数组并不保存键本身,而是通过键对象生成一个对象,将其作为数组的下表,这个数字就是散列码。
- 不同的键可以产生相同的下标,为了解决数组容量被固定的问题,相当于换算的键可能冲突。冲突通过外部链接处理,即链表。然后对链表中的值调用equals的方法进行线性查询。

### 持有引用(java.lang.ref)
## 持有引用(java.lang.ref)
- SoftReference用以实现内存敏感的高速缓存。
- WeakReference是为实现“规范映射”而设计的,它不妨碍垃圾回收器回收映射的键和值。
- PhantomReference用以调度回收前的清理工作,它比java机制更成熟。
- 引用的强弱顺序,为SoftReference、WeakReference、PhantomReference

### 性能测试
## 性能测试
- List 的结果如下
```
--------------------- ArrayList ---------------------
Expand Down
38 changes: 19 additions & 19 deletions src/main/java/com/learning/concurrent/CONCURRENT_BOOK.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
### 线程
#### 线程状态
# 线程
## 线程状态
![avatar](https://github.com/rbmonster/learning-note/blob/master/src/main/java/com/learning/concurrent/picture/threadState.jpg)

- 新建(NEW):创建后尚未启动。
Expand Down Expand Up @@ -27,7 +27,7 @@

- 死亡(TERMINATED):可以是线程结束任务之后自己结束,或者产生了异常而结束。

#### 创建一个线程的开销
## 创建一个线程的开销
- JVM 在背后帮我们做了哪些事情:

1. 它为一个线程栈分配内存,该栈为每个线程方法调用保存一个栈帧
Expand All @@ -44,8 +44,8 @@
- 用 Java8 的测试结果,19个线程,预留和提交的大概都是19000+KB,平均每个线程大概需要 1M 左右的大小

![avatar](https://github.com/rbmonster/learning-note/blob/master/src/main/java/com/learning/concurrent/picture/threadState2.jpg)
### 线程池
#### 线程池状态
## 线程池
### 线程池状态
线程池的5种状态:Running、ShutDown、Stop、Tidying、Terminated。
![avatar](https://github.com/rbmonster/learning-note/blob/master/src/main/java/com/learning/concurrent/picture/threadPool.jpg)

Expand All @@ -68,7 +68,7 @@
- TERMINATED
1. 状态说明:线程池彻底终止,就变成TERMINATED状态。
2. 状态切换:线程池处在TIDYING状态时,执行完terminated()之后,就会由 TIDYING -> TERMINATED当线程池在STOP状态下,线程池中执行的任务为空时,就会由STOP -> TIDYING。
#### 线程池创建
### 线程池创建
- 线程池的初始化:
```
/**
Expand Down Expand Up @@ -102,13 +102,13 @@ public ThreadPoolExecutor(int corePoolSize,//线程池的核心线程数量
![avatar](https://github.com/rbmonster/learning-note/blob/master/src/main/java/com/learning/concurrent/picture/threadPoolProcess.jpg)


#### 阿里开发规范
### 阿里开发规范
- 线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。
- 说明: Executors 返回的线程池对象的弊端如下:
1. FixedThreadPool 和 SingleThreadPool:允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM。
2. CachedThreadPool 和 ScheduledThreadPool:允许的创建线程数量为 Integer.MAX_VALUE, 可能会创建大量的线程,从而导致 OOM。

#### 线程池的队列
## 线程池的队列

1. SynchronousQueue(CachedThreadPool) 类似交警只是指挥车辆,并不管理车辆
- SynchronousQueue没有容量,是无缓冲等待队列,是一个不存储元素的阻塞队列,会直接将任务交给消费者,必须等队列中的添加元素被消费后才能继续添加新的元素。超出直接corePoolSize个任务,直接创建新的线程来执行任务,直到(corePoolSize+新建线程)> maximumPoolSize。不是核心线程就是新建线程。
Expand All @@ -119,7 +119,7 @@ public ThreadPoolExecutor(int corePoolSize,//线程池的核心线程数量
3. ArrayBlockingQueue
- ArrayBlockingQueue是一个有界缓存等待队列,可以指定缓存队列的大小,当正在执行的线程数等于corePoolSize时,多余的元素缓存在ArrayBlockingQueue队列中等待有空闲的线程时继续执行,当ArrayBlockingQueue已满时,加入ArrayBlockingQueue失败,会开启新的线程去执行,当线程数已经达到最大的maximumPoolSizes时,再有新的元素尝试加入ArrayBlockingQueue时会报错

#### 线上线程池的配置
### 线上线程池的配置
- CPU密集: CPU密集的意思是该任务需要大量的运算,而没有阻塞,CPU一直全速运行。
- CPU密集任务只有在真正的多核CPU上才可能得到加速(通过多线程),而在单核CPU上,无论你开几个模拟的多线程,该任务都不可能得到加速,因为CPU总的运算能力就那些。
- IO密集型,即该任务需要大量的IO,即大量的阻塞。在单线程上运行IO密集型的任务会导致浪费大量的CPU运算能力浪费在等待。所以在IO密集型任务中使用多线程可以大大的加速程序运行,即时在单核CPU上,这种加速主要就是利用了被浪费掉的阻塞时间。
Expand Down Expand Up @@ -156,19 +156,19 @@ public ThreadPoolExecutor(int corePoolSize,//线程池的核心线程数量
> 假设: 1-p=5% 而n趋近于无穷大,实际起作用的最大线程数为20。
> 临界区都是串行的,非临界区都是并行的,用单线程执行 临界区的时间/用单线程执行(临界区+非临界区)的时间 就是串行百分比
### 解决共享资源竞争
## 解决共享资源竞争

#### synchronized:
### synchronized:
- 在对象上调用其任意的synchronized方法的时候,此对象都会被加锁,此时该对象的其他synchronized方法只有等到前一个方法调用完毕,并释放了锁之后才能被调用。
- 如果一个方法在同一个对象上调用了第二个方法,后者又调用了同一对象上的另一个方法。JVM负责跟踪对象被加锁的次数,在任务第一次给对象加锁的时候,计数变为1,每当这个相同的任务在这个对象上获得锁时,技术都会增加,每当任务离开一个synchronized的方法,计数递减。当计数为0时,锁完全释放。(前提是首先获得了锁的任务才能允许继续获取多个锁)
- 针对每个类,也有一个锁(作为类的Class对象的一部分),所以synchronized static 方法可以在类的范围内防止对static数据的并发访问。
- 对比synchronized 同步方法和同步控制块的效率,同步控制块对象不加锁的时间更长,效率更高。

#### lock对象
### lock对象
- ReentrantLock 允许尝试着获取但最终未获取锁。
- 相比于synchronized锁,lock对象可以做到更细粒度的控制力。

#### 原子性
### 原子性
- 原子操作是不能被线程调度机制中断的操作,一旦操作开始,那么它一定可以在可能发生的,线程上下文切换操作之前执行完毕。
- 原子性可以应用于除long和double之外的所有基本类型之上的基本操作。
- 因为JVM可以将64位(long和double变量)的读取和写入当做两个分离的32位操作来执行,这就产生了在一个读取和写入操作中间发生上下文切换,从而导致结果有误。当然加上volatile,就能获得原子性。
Expand Down Expand Up @@ -213,11 +213,11 @@ void f2();
### 有序性
- 定义:本线程中,执行结果一致,但其他线程观察其过程是无序的。指的是“指令重排序”和“工作内存与主内存同步延迟”的现象。

#### ThreadLocal
## ThreadLocal
- 通常当做静态域存储,因为ThreadLocal为每个线程都分配了自己的空间。使用当前线程作为key,因此不会出现线程冲突。
- 注意不同线程在ThreadLocal存储的值为同一个对象的情况,由于引用都是同一个对象,因此会出现线程问题。

#### 退出线程的方法
## 退出线程的方法
- 与synchronized相关
1. 线程中使用一个静态的volatile的标志判断退出。
2. 调用Executors的submit方法,获取线程上下文对象Future,调用cancel方法。(注:无法中断正在试图获取synchronized锁或者试图执行I/O操作的线程)IO的中断,关闭底层资源之后,任务将解除阻塞。如socket连接,调用socket的close 或者 system.in 的输入连接调用in.close().
Expand All @@ -233,26 +233,26 @@ void f2();
- 此线程在运行中, 则不会收到提醒。但是 此线程的 “打扰标志”会被设置, 可以通过isInterrupted()查看并 作出处理。
- 结论:lockInterruptibly()和上面的第一种情况是一样的, 线程在请求lock并被阻塞时,如果被interrupt,则“此线程会被唤醒并被要求处理InterruptedException”。并且如果线程已经被interrupt,再使用lockInterruptibly的时候,此线程也会被要求处理interruptedException

### daemon Thread 守护线程应用场景
## daemon Thread 守护线程应用场景
- 典型的应用场景就是java的GC垃圾回收线程
- 平常在系统的应用中,同样可以用于缓存清理这方面的工作
- 固定取消过期订单。

### 线程间协作
## 线程间协作
1. wait()、notify()以及notifyAll()是基类Object的方法,尽管是线程的操作,放到基类中,便于操作所有对象。而这三个方法只能在==同步方法或者同步控制块中调用==。如果在非同步控制方法调用,程序能通过,但是运行时会得到IllegalMonitorStateException,表示调用该方法必须获得对象锁。
2. notifyAll()的并不是唤醒所有正在等待的任务。本质是notifyALl()因特定锁而被调用时,只有等待这个锁的任务才会被唤醒。
3. 使用ReentrantLock,通过lock.newCondition(),使用lock的signAll的方法实现线程间的协作
4. 使用BlockingQueue,阻塞队列来实现线程间协作,就可以较少很多繁杂的wait和notify操作。
- 通常可以使用LinkedBlockingQueue一个无界队列,ArrayBlockingQueue一个固定尺寸的队列。SynchronousQueue 只能包含一个元素的队列。
5.管道通信,线程之间通过管道进行连接传输信息。涉及的类PipedWriter和PipedReader,两者需要建立管道连接new PipedReader(sender.getPipedWriter())。

### 死锁产生条件
## 死锁产生条件
1.互斥条件:任务使用的资源至少有一个不能共享。
2.至少有一个任务它必须持有一个资源,且正在等待获取当前被别的任务持有的资源。
3.资源不能被任务抢占,必须等待。(资源必须等别的任务使用完成释放)
4.必须有等待循环。(即一个任务等待其他任务的资源,一个循环的等待)

### 其他的一些工具类
## 其他的一些工具类
- CountDownLatch计时器,主要方法countDown()、await()
- CyclicBarrier 栅栏,主要方法await(), 实例化可指定拦截的数量,和一个栅栏动作,一个自动执行的线程。
- DelayQueue 无界的BlockingQueue,用于放置实现了Delayed接口(在一段时间后只运行一次,其中的对象只能在其到期时才能从队列中取走)的对象
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/learning/design/adapter/ADAPTER.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
### 适配器模式
# 适配器模式
- 适配器模式,作为连接两个接口的桥梁,把一个类的接口变换成客户端所期待的另一种接口,从而使原本接口不匹配而无法一起工作的两个类能够在一起工作。

- target: 期待调用的接口
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/com/toc/ADAPTER.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<a name="index">**Index**</a>

&emsp;&emsp;<a href="#0">9.11. 适配器模式</a>
### <a name="0">适配器模式</a><a style="float:right;text-decoration:none;" href="#index">[Top]</a>
<a href="#0">适配器模式</a>
# <a name="0">适配器模式</a><a style="float:right;text-decoration:none;" href="#index">[Top]</a>
- 适配器模式,作为连接两个接口的桥梁,把一个类的接口变换成客户端所期待的另一种接口,从而使原本接口不匹配而无法一起工作的两个类能够在一起工作。

- target: 期待调用的接口
Expand Down
Loading

0 comments on commit 23ebd1d

Please sign in to comment.