# pray-analysis-backend
**Repository Path**: rainyheights/pray-analysis-backend
## Basic Information
- **Project Name**: pray-analysis-backend
- **Description**: 来帮助up提出你的bug修改建议
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2023-08-30
- **Last Updated**: 2024-01-18
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# Java 并发编程
### 轻量级锁:
检查当前对象的mark word是否有被其他线程占用,假如没有就会在当前栈帧里面建立一个
锁记录,复制并存储当前对象的mark word 信息。
不像重量级锁需要向系统申请互斥量,
### CAS(无锁算法)

显然,当cas失败的时候,说明有线程进入了这个同步代码块,这个时候,虚拟机将会检查
当前对象的mark word是否指向当前对象的栈帧,是的话就说明当前已经获得锁,否则不是-》退化为重量级锁(不可逆)
解锁时,同样使用CAS算法操作,同时唤醒挂起的线程
### 偏向锁
当某个锁频繁的被同一个线程获取,对轻量级锁进行优化,所以偏向锁专门为单个线程服务,此时,无须再进行CAS操作,当其他线程
又开始抢锁,偏向锁可能退化为轻量级锁。注意当调用对象的hashCode()方法,由于mark word 数据结构无法
保存hash值,偏向锁直接退化为轻量级锁。
锁的退化不可逆
### 锁消除和锁优化
代码块中有可能不会总是出现请求锁和释放锁的问题,(比如循环中加锁),此时锁为了优化出现锁消除和锁优化
## Java内存模型(JMM)

主内存: 存放对象实例的部分
工作内存:虚拟机栈的部分,放入cpu的高速缓存里面。 自增操作不是由一个指令实现的!!!包括获取,修改和保存
```java
class Test{
private static volatile int sum=0;//成员变量,这样的变量必须是当前的对象所拥有的
//加入了volatile关键字之后,线程之间可以感知彼此的值
@Test
void LockTestAdd() throws InterruptedException {
//没有加锁的时候,由于线程之间不能感知对方的值,最终结构可能不会是200
Thread th1 = new Thread(() -> {
for (int i = 0; i < 100; i++)
sum++;
});
Thread th2 = new Thread(() -> {
for (int i = 0; i < 100; i++)
sum++;
});
th1.start();
th2.start();
Thread.sleep(100);
System.out.println(sum);
}
}
```
### 重排序
由于JVM虚拟机和编译器的优化,指令可能出现重排序,在这种情况下可能出现不符合预期的情况
### volatile关键字(无法保证原子性,但能保证可见性)

load和save操作,将主内存中的变量拷贝到本地,只对本地变量进行操作。
volatile实现原理就是改变成员变量时,save的工作区的变量无效。重新更新主内存中的变量值,
volatile关键字会禁止指令重排序。

```java
class VolatileTest{
private static volatile int sum=0;//成员变量,这样的变量必须是当前的对象所拥有的
//加入了volatile关键字之后,线程之间可以感知彼此的值,但还是无法保证原子性操作,不能达到预期效果
@Test
void LockTestAdd() throws InterruptedException {
//没有加锁的时候,由于线程之间不能感知对方的值,最终结构可能不会是200
Thread th1 = new Thread(() -> {
for (int i = 0; i < 1000; i++)
sum++;
});
Thread th2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
sum++;
}
});
th1.start();
th2.start();
Thread.sleep(100);
System.out.println(sum);
}
}
```
JVM编译器下面的顺序执行:
### Happens Before 原则(之前的对之后的可见)
程序次序规则,监视器锁原则,volatile关键字原则(写操作在读操作之前),
#### start(线程启动规则)
A线程用start调用B线程,那么A在B之前(A happens before B)
#### join线程加入规则
A线程join线程B,那么B在A之前(B happens before A)
#### 程和线程的区别
程序软件 > 进程 > 线程
### 锁的框:Lock
为了代替传统的synchronized,notify,wait,notifyAll关键字,Lock接口->ReentrantLock可重入锁

## 可重入锁(排他锁)
多次加锁,其他线程想要得到锁需要把多次的锁释放才可以获取这把锁
当存在线程想要获取锁但是锁没有释放的时候,此时这些线程将会进入线程队列里面
### 公平锁和非公平锁(AQS)

公平锁始终保持先到先得到锁,非公平锁则是在等待队列中所有等待线程同时尝试获取锁,获取不到则再次进入等待队列
```txt
ReentrantLock lock=new ReentrantLock(false);//公平锁不一定总是保持公平。队列同步器
Runnable runnable=()->{
System.out.println(Thread.currentThread().getName() + "开始尝试获取锁资源");
lock.lock();
System.out.println(Thread.currentThread().getName() + "成功😺😺😺😺😺😺😺😺😺获取锁资源");
lock.unlock();
};
for (int i = 0; i < 10; i++) {
new Thread(runnable,"T"+i).start();
}
```
### 读写锁:
> 除了可重入锁之外,还有一种类型的锁叫做读写锁,当然它并不是专门用作读写操作的锁,
> 它和可重入锁不同的地方在于,可重入锁是一种排他锁,当一个线程得到锁之后,另一个线程必须等待其释放锁,否则一律不允许获取到锁。而读写锁在同一时间,是可以让多个线程获取到锁的,它其实就是针对于读写场景而出现的。
>
> 读写锁维护了一个读锁和一个写锁,这两个锁的机制是不同的。
>
> 读锁:在没有任何线程占用写锁的情况下,同一时间可以有多个线程加读锁。
>
> 写锁:在没有任何线程占用读锁的情况下,同一时间只能有一个线程加写锁。
显然读锁是可以重复获取的但是写锁不能,当一个线程同时拥有写锁和读锁的时候,先申请读锁
然后释放写锁,此时其他的线程又可以获取读锁,只剩下读锁,此时称之为“锁降级”。
在仅仅持有读锁的时候去申请写锁,称为“锁升级”,这时候ReentryReadWriteLock类不支持。
### 队列同步器AQS(AbstractQueuedSynchronizer)
继承关系:Lock-> Sync -> AbstractQueuedSynchronizer
### 多线程并发环境下的ABA问题
```java
//ABA问题的版本号解决方法
AtomicReference atomicReference=new AtomicReference<>("A");
System.out.println(atomicReference.compareAndSet("a", "c"));
String hello = "hello";
String world = "world";
Runnable r=()->{
System.out.println(atomicReference.compareAndSet("A", "B"));
};
for (int i = 0; i < 100; i++) {
new Thread(r).start();
}
```
可以看到多个线程尝试去修改的时候出现了一个true
解决办法:添加版本号,每次修改的时候对版本号(stamp)进行修正
## 并发容器
比如在对链表添加元素的时候,还没有完成对链表扩容之前,其他线程插队,非法插入元素,就会造成数组越界的报错。
* ConcurrentHashMap:在jdk1.7之前的实现方法,比如在原子类里面实现LongAdder具有压力分散的思想,提高了性能,选择将数据一段一段的存储,这样就减少了等待,当线程访问锁的时候只占用锁的一小部分
* jdk8之后,实现方法是通过cas算法配合锁机制实现的。由于HashMap利用了哈希表,容量越大,加锁的粒度就会越细。
```java
//原子类的测试操作
//ABA问题的版本号解决方法
CopyOnWriteArrayList