文章转载自http://www.importnew.com/22078.html

悲观锁和乐观锁

我们都知道,CPU是时分复用的,就是CPU把时间片,分配给不同的thread/process轮流执行,时间片与时间片之间,需要进行CPU切换,也就是会发生进程的切换。切换涉及到清空寄存器、缓存数据。然后重新加载新的thread所需数据。当一个线程被挂起时,加入到阻塞队列,在一定的时间或条件下,通过notify(),notifyAll()唤醒回来。在某个资源不可用的时候,就把CPU让出去,把当前的线程切换到阻塞状态。等到资源(如一个共享数据)可用了,就将线程唤醒,让他进入runnable状态等待CPU调度。这就是典型的悲观锁实现。独占锁是一种悲观锁,synchronized就是一种独占锁,他假设最坏的情况,并且只有在确保其他线程不会造成干扰的情况下执行,会导致其他所有需要锁的线程挂起,等待持有锁的线程释放锁。

但是,由于在进程挂起和恢复执行过程中存在着很大额开销。当一个线程正在等待锁时,他不能做任何事情,所有悲观锁有很大的缺点。举个例子,如果线程需要某个资源,但是资源的占用时间很短,当线程第一次抢占这个资源时,可能这个资源被占用,如果此时挂起这个线程,可能立刻就发现资源可用,然后有需要花费很长的时间重新抢占锁,时间代价就会非常的高。

所以就有的乐观锁的概念,他的核心思路就是:每次不加锁而是假设没有冲突而去完成某项操作,如果因为冲突失败就重试,知道成功为止。在上面的例子中,某个线程可以不让出CPU,而是一直WHILE循环,如果失败就重试,直到成功为止。所以,当数据争用不严重的时,乐观锁效果更好,比如CAS就是一种乐观锁思想的应用。

Java中CAS的实现

CAS就是Compare and Swap的意思,比较并操作。很多的CPU直接支持CAS指令。CAS是项乐观锁技术,当多个线程尝试使用CAS同时更新一个变量时,只有其中一个线程能够更新变量的值,而其他线程都失败,失败的线程不会被挂起,而是被告知此次竞争失败,并可以再次尝试。CAS有3个操作数,内存值V,就的预期值A,要修改的新值B。当且仅当预期值A与内存值V相同时,将内存值修改为B,否则什么都不做。

JDK1.5中引人了底层的支持,在INT、long和对象的引用等类型上都公开的CAS操作,并且JVM把他们编译为底层硬件提供的最有效的方法,在运行CAS的平台上,运行时把他们编译为相应的机器指令。在java.util.concurrent.atmoic包下面所有的原子变量类型中,比如AtomicInteger,都使用了这些底层的JVM支持为数字类型的引用提供了一种高效的CAS操作。

在CAS操作中会出现ABA问题。就是如果V值现有A变B,再由B变A,那么仍然认为是发生了变化,并且需要重新执行算法中的步骤。有个简单的解决方案:不是更新某个引用的值,而是更新两个值,包括一个引用和一个版本号,即使这个值由A变B,然后变为A,版本号也是不同的。AtomicStampedReference和AtomicMarkableReference支持在两个变量上执行原子的条件更新。AtomicStampedReference更新一个“对象-引用”二元组,通过在引用上加上“版本号”,从而避免“ABA”问题,AtomicMarkableReference将更新一个“对象引用-布尔值”的二元组。

AtomicInteger的实现

AtomicInteger是一个支持原子操作的Integer类,就是保证AtomicInteger类型变量的增加和减少操作是原子性的,不会出现多个线程下数据不一致的问题。如果不使用AtomicInteger,要实现一个按顺序获取的ID,就必须在每次获取时进行加锁操作,以避免出现并发时获取到同样ID的现象。

编程语言java-并发(锁)的更多相关文章

  1. 深入理解 Java 并发锁

    本文以及示例源码已归档在 javacore 一.并发锁简介 确保线程安全最常见的做法是利用锁机制(Lock.sychronized)来对共享数据做互斥同步,这样在同一个时刻,只有一个线程可以执行某个方 ...

  2. Java 并发锁

    Java 中的锁 阻塞锁.可重入锁.读写锁.互斥锁.悲观锁.乐观锁.公平锁.偏向锁.对象锁.线程锁.锁粗化.锁消除.轻量级锁.重量级锁.信号量.独享锁.共享锁.分段锁 一.常见的锁 synchroni ...

  3. java并发锁ReentrantReadWriteLock读写锁源码分析

    1.ReentrantReadWriterLock 基础 所谓读写锁,是对访问资源共享锁和排斥锁,一般的重入性语义为如果对资源加了写锁,其他线程无法再获得写锁与读锁,但是持有写锁的线程,可以对资源加读 ...

  4. 如何理解Java中眼花缭乱的各种并发锁?

    在互联网公司面试中,很多小伙伴都被问到过关于锁的问题. 今天,我给大家一次性把Java并发锁的全家桶彻底讲明白.包括互斥锁.读写锁.重入锁.公平锁.悲观锁.自旋锁.偏向锁等等等等.视频有点长,大家一定 ...

  5. 百万并发中间件系统的内核设计看Java并发性能优化

    “ 这篇文章,给大家聊聊一个百万级并发的中间件系统的内核代码里的锁性能优化. 很多同学都对Java并发编程很感兴趣,学习了很多相关的技术和知识.比如volatile.Atomic.synchroniz ...

  6. 深入并发锁,解析Synchronized锁升级

    这篇文章分为六个部分,不同特性的锁分类,并发锁的不同设计,Synchronized中的锁升级,ReentrantLock和ReadWriteLock的应用,帮助你梳理 Java 并发锁及相关的操作. ...

  7. Java 并发机制底层实现 —— volatile 原理、synchronize 锁优化机制

    本书部分摘自<Java 并发编程的艺术> 概述 相信大家都很熟悉如何使用 Java 编写处理并发的代码,也知道 Java 代码在编译后变成 Class 字节码,字节码被类加载器加载到 JV ...

  8. 【Java并发编程实战】----- AQS(二):获取锁、释放锁

    上篇博客稍微介绍了一下AQS,下面我们来关注下AQS的所获取和锁释放. AQS锁获取 AQS包含如下几个方法: acquire(int arg):以独占模式获取对象,忽略中断. acquireInte ...

  9. 【Java并发编程实战】-----“J.U.C”:CLH队列锁

    在前面介绍的几篇博客中总是提到CLH队列,在AQS中CLH队列是维护一组线程的严格按照FIFO的队列.他能够确保无饥饿,严格的先来先服务的公平性.下图是CLH队列节点的示意图: 在CLH队列的节点QN ...

  10. 【Java并发系列04】线程锁synchronized和Lock和volatile和Condition

    img { border: solid 1px } 一.前言 多线程怎么防止竞争资源,即防止对同一资源进行并发操作,那就是使用加锁机制.这是Java并发编程中必须要理解的一个知识点.其实使用起来还是比 ...

随机推荐

  1. 61. Unique Paths && Unique Paths II

    Unique Paths A robot is located at the top-left corner of a m x n grid (marked 'Start' in the diagra ...

  2. shell 初学者 必读 ,强烈推荐新手读

    背景: 很多人从C/C++转化而来,看了学习文档之后,踩入了很多坑 1 对变量赋值 不要有空格 a=123 # 正确 a = 123 # 错误 2  if语句 [] 要留有空格,变量最好加" ...

  3. Flex布局总结

    2009年,W3C提出了一种新的方案----Flex布局,可以简便.完整.响应式地实现各种页面布局.目前,它已经得到了所有浏览器的支持,这意味着,现在就能很安全地使用这项功能.lex布局将成为未来布局 ...

  4. 前端项目构建error

    Refusing to install webpack as a dependency of itself 原因:package.json中,"name": "webpa ...

  5. MyBatis学习总结(八)——Mybatis3.x与Spring4.x整合

    一.搭建开发环境 1.1.使用Maven创建Web项目 执行如下命令: mvn archetype:create -DgroupId=me.gacl -DartifactId=spring4-myba ...

  6. NHibernate系列文章十一:NHibernate并发控制

    摘要 在同一时刻数据访问量和更新次数比较大的系统中,产生了数据的并发访问问题.并发访问使得在这样的环境中,所有用户(程序.实际用户.进程.线程等)的操作不产生负面问题. 如果不使用并发,在两个用户同时 ...

  7. jQuery 根据JSON数据动态生成表格

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/ ...

  8. Mysql数据库的使用经验总结

    1. 对mysql插入中文的时候显示乱码,搞了很多天,把服务端.客户端和数据库的编码全改为u8了又重新创建数据库和表还是不行,到最后却发现没有乱码!原来只是windows的cmd没有支持u8,换个客户 ...

  9. frame中隐藏横向滚动条

    设置frame的scrolling="yes",在右侧页面的body里加入: style="overflow-x:hidden;"  如:<body st ...

  10. PHP面向对象的标准

    (1)所有数据都应该隐藏在所在的类的内部. (2)类的使用者必须依赖类的共有接口,但类不能依赖它的使用者. (3)尽量减少类的协议中的消息. (4)实现所有类都理解的最基本公有接口[例如,拷贝操作(深 ...