分类

悲观锁和乐观锁
一种广义的概念,线程同步的不同的角度
| 含义 | 实现 | 使用场景 | |
|---|---|---|---|
| 悲观锁 | 悲观锁认为在使用数据的时候,一定有别的线程来修改数据,在获取数据的时候会先加锁,确保数据不会被别的线程修改。 | 关键字synchronized、接口Lock的实现类 | 写操作较多,先加锁可以保证写操作是数据正确 |
| 乐观锁 | 乐观锁认为自己在使用数据的时候不会有其他的线程修改数据,所以不会添加锁,只是在更新数据的时候去判断之前有没有别的线程更新了这个数据 | CAS算法 | 读操作较多,不加锁的特点能够使其读操作的性能大幅提升 |
阻塞锁和自旋锁
| 含义 | 缺点 | |
|---|---|---|
| 阻塞锁 | 线程在获取不到锁的时候,会阻塞住 | 性能降低 |
| 自旋锁 | 线程在获取不到锁的时候,线程将循环等待,然后不断判断是否能够被成功获取,自旋知道获取到锁才会退出循环 | 循环会消耗CPU |
自旋是通过CAS算法实现的
无锁、偏向锁、轻量锁、重量锁
1-4 是锁升级,具体实现是synchronized(jdk1.6之后)
- 无锁
不锁住资源 - 偏向锁
只有一个线程进入临界区,适用于只有一个线程访问同步块的场景 - 轻量锁
多线程未竞争或竞争不激烈,适用于追求响应时间,同步块执行速度非常快(自旋CAS算法) - 重量锁
多个线程竞争激烈,只让一个线程运行,其余的线程都阻塞
可重入锁和不可重入锁
重入的理解:一个线程可以多次获得同一把锁并通过state记录加了多少锁
公平锁和非公平锁
公平的理解:线程排队获取锁是否遵循先到先得的规则
互斥锁和共享锁
| 含义 | 使用 | |
|---|---|---|
| 互斥锁 | 在访问共享资源之前对进行加锁操作,在访问完成之后进行解锁操作。 加锁后,任何其他试图再次加锁的线程会被阻塞,直到当前进程解锁 | synchronized,ReentrantLock |
| 共享锁 | 共享锁从字面来看也即是允许多个线程共同访问资源 | Semapore信号量和ReentrantReadWriteLocK |
实现
synchronized
悲观锁,(无锁、偏向锁、轻量锁、重量锁是jdk1.6之后),可重入锁,非公平锁,互斥锁
依赖于 JVM 实现
| 场景 | 示例 | 含义 |
|---|---|---|
| 代码块 | synchronized (对象){...} | 对象为this,则为代码块所在类的对象锁 |
| 静态方法 | synchronized void run() { ...} | 所在类的对象锁 |
| 普通方法 | synchronized static void run() { ...} | 所在类的类锁 |
详情请参考《synchronized详解》
Lock


从上面两个类图结构,可以看出Lock接口是锁的所需要实现的接口;而锁,信号量的实现基于Sync,Sync继承于AQS;
AQS是什么呢?
字面意思,抽象的同步器队列。请参考《AQS》
本文详细解析了线程锁的多种类型,包括悲观锁、乐观锁、阻塞锁、自旋锁等,并探讨了它们的实现原理及适用场景。同时,文章还介绍了无锁、偏向锁、轻量锁、重量锁、可重入锁、公平锁和非公平锁、互斥锁和共享锁的区别,以及synchronized和Lock接口的使用方法。

1815

被折叠的 条评论
为什么被折叠?



