悲观者与乐观者的作事方式彻底不同,悲观者的人生观是一件事情我必需要百分之百彻底控制才会去作,不然就认为这件事情必定会出问题;而乐观者的人生观则相反,凡事无论最终结果如何,他都会先尝试去作,大不了最后不成功。这就是悲观锁与乐观锁的区别,悲观锁会把整个对象加锁占为自有后才去作操做,乐观锁不获取锁直接作操做,而后经过必定检测手段决定是否更新数据。这一节将对乐观锁进行深刻探讨。算法
前面用Synchronized互斥锁属于悲观锁,它有一个明显的缺点,它无论数据存不存在竞争都加锁,随着并发量增长,且若是锁的时间比较长,其性能开销将会变得很大。有没有办法解决这个问题?答案是基于冲突检测的乐观锁。这种模式下,已经没有所谓的锁概念了,每条线程都直接先去执行操做,计算完成后检测是否与其余线程存在共享数据竞争,若是没有则让此操做成功,若是存在共享数据竞争则可能不断地从新执行操做和检测,直到成功为止,可叫CAS自旋。bash
乐观锁的核心算法是CAS(Compare and Swap),它涉及到三个操做数:内存值、预期值、新值。当且仅当预期值和内存值相等时才将内存值修改成新值。这样处理的逻辑是,首先检查某块内存的值是否跟以前我读取时的同样,如不同则表示期间此内存值已经被别的线程更改过,舍弃本次操做,不然说明期间没有其余线程对此内存值操做,能够把新值设置给此块内存。如图,有两个线程可能会差很少同时对某内存操做,线程二先读取某内存值做为预期值,执行到某处时线程二决定将新值设置到内存块中,若是线程一在此期间修改了内存块,则经过CAS便可以检测出来,假如检测没问题则线程二将新值赋予内存块。并发
public class AtomicInt {
private volatile int value;
public final int get() {
return value;
}
public final int getAndIncrement() {
for (;;) {
int current = get();
int next = current + 1;
if (compareAndSet(current, next))
return current;
}
}
public final boolean compareAndSet(int expect, int update) {
Unsafe类提供的硬件级别的compareAndSwapInt方法;
}
}
复制代码
其中最重要的方法是getAndIncrement方法,它里面实现了基于CAS的自旋。 如今已经了解乐观锁及CAS相关机制,乐观锁避免了悲观锁独占对象的现象,同时也提升了并发性能,但它也有缺点:机器学习
乐观锁是对悲观锁的改进,虽然它也有缺点,但它确实已经成为提升并发性能的主要手段,并且jdk中的并发包也大量使用基于CAS的乐观锁。分布式
-------------推荐阅读------------高并发
跟我交流,向我提问:
公众号的菜单已分为“分布式”、“机器学习”、“深度学习”、“NLP”、“Java深度”、“Java并发核心”、“JDK源码”、“Tomcat内核”等,可能有一款适合你的胃口。
欢迎关注: