内容简介:本文翻译和原创各占一半,所以还是厚颜无耻归类到原创好了...java 5 其中一个令人振奋的改进是新增了支持原子操作的类型,例如
本文翻译和原创各占一半,所以还是厚颜无耻归类到原创好了...
https://howtodoinjava.com/jav...
java 5 其中一个令人振奋的改进是新增了支持原子操作的类型,例如 AtomicInteger
, AtomicLong
等。在多线程环境中进行简单的自增自减操作时,这些原子类能帮助你减少很多用于多线程同步的复杂代码。这些原子类依赖于 CAS (compare and swap) 算法,接下来我们会讨论 CAS 这个概念。
乐观锁和悲观锁
传统的锁机制,例如 java 的 synchronized
关键字,他代表了 java 中悲观锁技术,保证了某一时刻仅有一个线程能访问同步代码/方法。 synchronized
能够很好地工作,却有着 (相对) 比较大的性能开销。
乐观锁 (相对悲观锁) 对性能会有很大的帮助。他的核心思想是:你寄希望于在没有冲突的情况下完成一次更新操作,使用乐观锁技术更新时会进行 “冲突检测” 来判断是否有其他的线程干扰,若是 (有其他线程干扰) 则视本次更新操作失败,一般会进行重试 (可以了解一下CAS自旋)。 Compare and Swap
就是典型的乐观锁技术。
CAS 算法
CAS 算法会先 对一个内存变量(位置) V 和一个给定的值进行比较 A
,如果相等,则 用一个新值 B 去修改这个内存变量(位置)
。上述过程会作为一个原子操作完成 (intel处理器通过 cmpxchg
指令系列实现)。CAS 原子性保证了新值的计算是基于上一个有效值,期间如果内存变量(位置) V
被其他线程更新了,本线程的 CAS 更新操作将会失败。CAS 操作必须告诉调用者成功与否,可以返回一个 boolean 值来表示,或者返回一个从内存变量读到的值 (应该是上一次有效值)
CAS 操作数有三个:
- 内存变量(位置) V ,表示被更新的变量
- 线程上一次读到的旧值 A
- 用来覆盖 V 的新值 B
CAS 表示:“我认为现在 V 的值还是之前我读到的旧值 A,若是则用新值 B 覆盖内存变量 V,否则不做任何动作并告诉调用者操作失败”。CAS 是一项乐观锁技术,他在更新的时候总是希望能成功 (没有冲突),但也能检测出来自其他线程的冲突和干扰
Java 中的 Compare and Swap
这里我们关注一下 ReentrantLock
锁定和解锁那部分的源码
//ReentrantLock.lock()
public void lock() {
sync.lock();
}
他依赖了其内部类 Sync
的 lock()
,以下是内部类 Sync
(继承了队列同步器 AQS)
abstract static class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = -5179523762034025860L;
abstract void lock();
................
Sync
还是个抽象类,一般 new ReentrantLock()
时创建的是 NonfairSync
// ReentrantLock的构造方法
public ReentrantLock() {
sync = new NonfairSync();
}
下面就是 NonfairSync
的 lock()
方法了
final void lock() {
if (compareAndSetState(0, 1)) // 1
setExclusiveOwnerThread(Thread.currentThread()); // 2
else
acquire(1); // 3
}
-
1 中的
compareAndSetState()承继自队列同步器 AQS,封装了 CAS 指令。因为是NonfairSync非公平锁,所以一上来就尝试抢占锁:给定旧值 0 并希望用新值 1 去更新内存变量 State。若更新成功则视为获取锁成功,并执行 2 - 2 成功完成了 CAS 操作 (没错,当你使用 CAS 指令成功把 State 从 0 更新成 1 便视为获取锁,就是这么简单粗暴 ╮(╯▽╰)╭ ),把当前线程设为独占线程
- 3 操作失败 (被人抢先获取锁(╯`□′)╯╧╧),进行 acquire 操作再次尝试获取锁,若还是不行,则把当前线程加入 AQS 等待队列,由 AQS 来管理队列中等待线程的阻塞和唤醒,具体代码就不贴出来了,AQS 的源码多处使用到 CAS 指令,有兴趣的同学可以查看
锁用完了要释放,下面贴出 unlock()
方法
// ReentrantLock.unlock()
public void unlock() {
sync.release(1);
}
这里还是依赖了 sync, release()
是 AQS 的通用方法,其内部调用了 tryRelease()
(由 Sync 类实现),这里直接贴出 Sync 的 tryRelease()
protected final boolean tryRelease(int releases) { // releases 参数的值是上面传进来的 1
int c = getState() - releases; // 1
if (Thread.currentThread() != getExclusiveOwnerThread()) // 1.5
throw new IllegalMonitorStateException();
boolean free = false;
if (c == 0) { // 2
free = true;
setExclusiveOwnerThread(null);
}
setState(c); // 3
return free;
}
ReentrantLock
Summary
AQS 队列同步器以及 java.util.concurrent
下各种锁和原子类都运用到的 CAS 算法,有时间的同学建议阅读加深印象。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 通俗易懂--决策树算法、随机森林算法讲解(算法+案例)
- 限流算法之漏桶算法、令牌桶算法
- 什么是Paxos算法?Paxos算法是区块链核心算法之一
- 一文读懂对称加密算法、非对称加密算法和Hash算法
- 算法(六):图解贪婪算法
- 算法篇03:排序算法
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Django 1.0 Template Development
Scott Newman / Packt / 2008 / 24.99
Django is a high-level Python web application framework designed to support the rapid development of dynamic websites, web applications, and web services. Getting the most out of its template system a......一起来看看 《Django 1.0 Template Development》 这本书的介绍吧!