<commit_before># 线程安全性
## 严格定义
当多个线程访问一个对象时，如果不用考虑这些线程运行时环境下的调度与交替运行，也不需要进行额外同步，或者在调用方法进行任何其他的协调工作，调用这个对象的行为可以获得正确的结果，那这个对象就是线程安全的。

## 线程安全等级划分
Java语言操作共享数据线程的安全程度划分（5级）：

1. 不可变
使用final修饰，使变量保持线程可见性，主要不可变对象构造出来（无this引用逃逸），其状态就是不可变的，不会出现线程不一致的情况。
> final修饰基本数据类型，可保证不可变；final修饰引用对象，保证对象的行为不会对对象状态产生影响（类似于String，考虑将对象中所有状态变量都变成final）。

2. 绝对线程安全
就是上一项给出的严格定义，Java中的线程安全类都不是严格定义的，例如：Vector，一个线程写，另一个线程删除，同样会产生错误。

3. 相对线程安全
弱化了绝对的定义，保证对象单个操作时线程安全的，但是针对单个对象的多次操作还是需要同步。

4. 线程兼容
对象本身不是线程安全，但是可以通过某一个些同步手段实现线程安全。（HashMap和ArrayList）

5. 线程对立
即使使用同步，也不能保证线程安全。（两个线程A,B，同时对C采用suspend()和resume()操作）。此外，还由System.setIn()、System.setOut()和System.runFinalizersOnExit()等。

## 实现方法
### 并发策略
- 乐观锁，假设不会发生并发冲突，只在提交操作时检查是否违反数据完整性。
- 悲观锁，假定会发生并发冲突，屏蔽一切可能违反数据完整性的操作。

> 互斥同步时一种悲观的并发策略，总是认为只要不去做正确的同步措施（例如加锁），那肯定会出现问题，无论共享数据是否真的会出现竞争，都要进行加锁（概念模型）。

### 细节描述
1. 同步互斥，互斥是因，同步时果。
    **同步**指的是在多个线程并发访问数据的时候，保证共享数据在同一时刻只被一个（或者一些）线程使用；**互斥**是实现同步的一种方式，临界区（Critical Section）、互斥量（Mutex）和信号量（Semaphore）。
    - Java中通过synchronized关键字实现，经过编译后同步块前后分别形成monitorenter和monitorexit两个指令码，这两个字节码接受reference类型参数来锁定和解锁对象。（如果有对象输入，则使用对象锁；如果无对象输入，则根据方法类型，实例方法对实例对象，类方法对类对象）
    - ReentrantLock，与synchronized类似，具备线程重入特性，本质上都是互斥锁，增加一些高级功能：
        - 等待可中断，长时间等待，可放弃；
        - 公平锁，多线程等待同一个锁，按照申请锁的时间顺序依次获得锁；
        - 一个ReentrantLock对象可以绑定多个Condition对象（newCondition），而sychronized包含一个隐含条件，但要与多于一个条件关联，需要额外加锁；<br>
> ReentrantLock表现在API层面的互斥锁（lock()和unlock() + try/finally语句块完成）；另一个表现在原生语法层面的互斥。JDK1.6之后，synchronized与ReentrantLock性能基本持平。

2. 非阻塞同步，乐观锁（基于冲突检测），基本思路先进行操作，如果没有冲突，则操作成功；如果产生冲突，采取补偿措施（例如：重试）。乐观锁的实现，需要CPU指令集的支持，因为检测冲突和操作（设置），需要保证原子性，如果采用锁，没有意义（互斥），而CPU提供CAS（Compare and Swap）指令支持。
> **CAS指令**，需要三个操作数，一个内存位置（V），旧的预期值（A），新值（B）。CAS执行时，当V符合旧预期值A时，处理器用新值B更新V的值，否则它不执行更新，该处理过程是一个原子操作。Java中Unsafe类的CAS操作，包括compareAndSet()和getAndIncrement()等方法。
> CAS存在一个**ABA问题**，当第一从V读取到A时，并且准备赋值操作，这期间如果有线程将值从A修改到B，又从B修改到A，那么CAS检测时会假定其没有被修改过。（J.U.C，java并发包，提供了一个AtomicStampedReference，通过控制变量的版本号保证CAS正确性）

3. 无同步代码
 - 可重入代码，一个方法，结果时可预测的，输入相同的数据，返回相同的结果。
 - 线程本地存储，共享数据的代码可否在一个线程内执行。


## sychronized（重量级锁）
## 使用
- 修饰实例方法，作用于当前实例加锁，进入同步代码前要获得当前实例的锁
- 修饰类方法）(static)，作用于当前类对象加锁，进入同步代码前要获得当前类对象的锁
- 修饰代码块，指定加锁对象，对给定对象加锁，进入同步代码块前要获得给定对象的锁。

## 底层实现
重量级锁也就是通常说synchronized的对象锁，锁标识位为10，其中指针指向的是monitor对象（也称为管程或监视器锁）的起始地址。每个对象都存在着一个 monitor 与之关联，对象与其 monitor 之间的关系有存在多种实现方式，如monitor可以与对象一起创建销毁或当线程试图获取对象锁时自动生成，但当一个 monitor 被某个线程持有后，它便处于锁定状态。在Java虚拟机(HotSpot)中，monitor是由ObjectMonitor实现。

Hotspot实现ObjectMonitor，维护两个队列，一个EntrySet，一个WaitSet，一个指向获得对象锁线程的指针Owner，线程刚进入竞争线程锁时，进入EntrySet；获取的线程，修改Owner指向该线程，并将计数器count加1；当线程调用wait时，进入WaitSet，清空Owner，count减1；当线程结束，同上，释放锁，其他线程竞争。



<commit_msg>Updates javase/concurrent/lock.md<commit_after># 线程安全性
## 严格定义
当多个线程访问一个对象时，如果不用考虑这些线程运行时环境下的调度与交替运行，也不需要进行额外同步，或者在调用方法进行任何其他的协调工作，调用这个对象的行为可以获得正确的结果，那这个对象就是线程安全的。

## 线程安全等级划分
Java语言操作共享数据线程的安全程度划分（5级）：

1. 不可变
使用final修饰，使变量保持线程可见性，主要不可变对象构造出来（无this引用逃逸），其状态就是不可变的，不会出现线程不一致的情况。
> final修饰基本数据类型，可保证不可变；final修饰引用对象，保证对象的行为不会对对象状态产生影响（类似于String，考虑将对象中所有状态变量都变成final）。

2. 绝对线程安全
就是上一项给出的严格定义，Java中的线程安全类都不是严格定义的，例如：Vector，一个线程写，另一个线程删除，同样会产生错误。

3. 相对线程安全
弱化了绝对的定义，保证对象单个操作时线程安全的，但是针对单个对象的多次操作还是需要同步。

4. 线程兼容
对象本身不是线程安全，但是可以通过某一个些同步手段实现线程安全。（HashMap和ArrayList）

5. 线程对立
即使使用同步，也不能保证线程安全。（两个线程A,B，同时对C采用suspend()和resume()操作）。此外，还由System.setIn()、System.setOut()和System.runFinalizersOnExit()等。

## 实现方法
### 并发策略
- 乐观锁，假设不会发生并发冲突，只在提交操作时检查是否违反数据完整性。
- 悲观锁，假定会发生并发冲突，屏蔽一切可能违反数据完整性的操作。

> 互斥同步时一种悲观的并发策略，总是认为只要不去做正确的同步措施（例如加锁），那肯定会出现问题，无论共享数据是否真的会出现竞争，都要进行加锁（概念模型）。

### 细节描述
1. 同步互斥，互斥是因，同步时果。
    **同步**指的是在多个线程并发访问数据的时候，保证共享数据在同一时刻只被一个（或者一些）线程使用；**互斥**是实现同步的一种方式，临界区（Critical Section）、互斥量（Mutex）和信号量（Semaphore）。
    - Java中通过synchronized关键字实现，经过编译后同步块前后分别形成monitorenter和monitorexit两个指令码，这两个字节码接受reference类型参数来锁定和解锁对象。（如果有对象输入，则使用对象锁；如果无对象输入，则根据方法类型，实例方法对实例对象，类方法对类对象）
    - ReentrantLock，与synchronized类似，具备线程重入特性，本质上都是互斥锁，增加一些高级功能：
        - 等待可中断，长时间等待，可放弃；
        - 公平锁，多线程等待同一个锁，按照申请锁的时间顺序依次获得锁；
        - 一个ReentrantLock对象可以绑定多个Condition对象（newCondition），而sychronized包含一个隐含条件，但要与多于一个条件关联，需要额外加锁；<br>
> ReentrantLock表现在API层面的互斥锁（lock()和unlock() + try/finally语句块完成）；另一个表现在原生语法层面的互斥。JDK1.6之后，synchronized与ReentrantLock性能基本持平。

2. 非阻塞同步，乐观锁（基于冲突检测），基本思路先进行操作，如果没有冲突，则操作成功；如果产生冲突，采取补偿措施（例如：重试）。乐观锁的实现，需要CPU指令集的支持，因为检测冲突和操作（设置），需要保证原子性，如果采用锁，没有意义（互斥），而CPU提供CAS（Compare and Swap）指令支持。
> **CAS指令**，需要三个操作数，一个内存位置（V），旧的预期值（A），新值（B）。CAS执行时，当V符合旧预期值A时，处理器用新值B更新V的值，否则它不执行更新，该处理过程是一个原子操作。Java中Unsafe类的CAS操作，包括compareAndSet()和getAndIncrement()等方法。
> CAS存在一个**ABA问题**，当第一从V读取到A时，并且准备赋值操作，这期间如果有线程将值从A修改到B，又从B修改到A，那么CAS检测时会假定其没有被修改过。（J.U.C，java并发包，提供了一个AtomicStampedReference，通过控制变量的版本号保证CAS正确性）

3. 无同步代码
 - 可重入代码，一个方法，结果时可预测的，输入相同的数据，返回相同的结果。
 - 线程本地存储，共享数据的代码可否在一个线程内执行。


## sychronized（重量级锁）

synchronized属于重量级锁，效率低下，因为监视器锁（monitor）是依赖于底层的操作系统的Mutex Lock来实现的，而操作系统实现线程之间的切换时需要从用户态转换到核心态。

## 使用
- 修饰实例方法，作用于当前实例加锁，进入同步代码前要获得当前实例的锁
- 修饰类方法）(static)，作用于当前类对象加锁，进入同步代码前要获得当前类对象的锁
- 修饰代码块，指定加锁对象，对给定对象加锁，进入同步代码块前要获得给定对象的锁。

## 底层实现
重量级锁也就是通常说synchronized的对象锁，锁标识位为10，其中指针指向的是monitor对象（也称为管程或监视器锁）的起始地址。每个对象都存在着一个 monitor 与之关联，对象与其 monitor 之间的关系有存在多种实现方式，如monitor可以与对象一起创建销毁或当线程试图获取对象锁时自动生成，但当一个 monitor 被某个线程持有后，它便处于锁定状态。在Java虚拟机(HotSpot)中，monitor是由ObjectMonitor实现。

Hotspot实现ObjectMonitor，维护两个队列，一个EntrySet，一个WaitSet，一个指向获得对象锁线程的指针Owner，线程刚进入竞争线程锁时，进入EntrySet；获取的线程，修改Owner指向该线程，并将计数器count加1；当线程调用wait时，进入WaitSet，清空Owner，count减1；当线程结束，同上，释放锁，其他线程竞争。所以，在java每个对象都能作为锁，而wait()/notify()等方法在Object对象中。（可重入的方式，通过monitor计数器count实现）

### sychronized代码块
字节码时通过monitorenter 和 monitorexit 指令圈定同步块。（编译器将会确保无论方法通过何种方式完成，方法中调用过的每条 monitorenter 指令都有执行其对应 monitorexit 指令，而无论这个方法是正常结束还是异常结束。编译器会自动产生一个异常处理器，这个异常处理器声明可处理所有的异常，它的目的就是用来执行 monitorexit 指令。）

### sychronized方法
JVM可以从方法常量池中的方法表结构(method_info Structure) 中的 ACC_SYNCHRONIZED 访问标志区分一个方法是否同步方法。




{'fraction_non_alphanumeric': 0.11371935315597287, 'fraction_numerical': 0.005216484089723527, 'mean_word_length': 14.338666666666667, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3187732', 'n_tokens_mistral': 4534, 'n_tokens_neox': 5325, 'n_words': 146}