基于锁的并发算法 vs 无锁的并发算法

原文链接 作者:Martin Thompson  译者:曹姚君 校对: 方腾飞

上周在由Heinz Kabutz通过JCrete 组织的开放空间会议(unconference)上,我参加一个新的java规范 JSR166 StampedLock的审查会议。StampedLock 是为了解决多个readers 并发访问共享状态时,系统出现的内存地址竞争问题。在设计上通过使用乐观的读操作,StampedLock 比ReentrantReadWriteLock 更加高效;

在会议期间,我突然意思到两点:

  • 第一、我想是时候该去回顾java中锁的实现的现状。
  • 第二、虽然StampedLock 看上去是JDK很好的补充,但是它视乎忽略了一个事实,即在多个reader的场景里,无锁的算法通常是更好的解决方案。

 测试:

为了比较不同的实现方式,我需要采用一种不偏向任意一方的API测试用例。 比如:API必须不产生垃圾、并且允许方法是原子性的。一个简单的测试用例是设计一个可在两维空间中移动其位置的太空船,它位置的坐标可以原子性的读取;每一次事物里至少需要读写2个域,这使得并发变得非常有趣;

01 /**
02  * 并发接口,表示太空船可以在2维的空间中移动位置;并且同时更新读取位置
03  */
04  public interface Spaceship
05  {
06  /**
07  * 读取太空船的位置到参数数组 coordinates 中
08  *
09  * @param coordinates 保存读取到的XY坐标.
10  * @return 当前的状态
11  */
12  int readPosition(final int[] coordinates);
13  
14 /**
15  * 通过增加XY的值表示移动太空船的位置。
16  *
17  * @param xDelta x坐标轴上移动的增量.
18  * @param yDelta y坐标轴上移动的增量.
19  * @return the number of attempts made to write the new coordinates.
20  */
21  int move(final int xDelta, final int yDelta);
22  }
23 <pre>

上面的API通过分解一个不变的位置对象,本身是干净的 。但是我想保证它不产生垃圾,并且需要能最直接的更新多个内容域。这个API可以很容易地扩展到三维空间,并实现原子性要求。

为每一个飞船都设置多个实现,并且作为一个测试套件。本文中所有的代码和结果都可以在这里找到。

测试套件会依次运行每一种实现.并且使用 megamorphic dispatch模式,防止并发访问中的方法内联(inlining),锁粗化(lock-coarsening),循环展开( loop unrolling)的问题;

每种实现都执行下面4个不同的线程的情况,结果也是不同的;

1 reader – 1 writer

2 readers – 1 writer

3 readers – 1 writer

2 readers – 2 writers

所有的测试运行在64位机器、Java版本:1.7.0_25、 Linux版本:3.6.30、4核 2.2GHz Ivy Bridge (第三代Core i系列处理器)i7-3632QM的环境上。

测试吞吐量的时候,是通过每一种实现都重复测试超过5次,每一次都运行5秒以上,以保证系统足够预热,下面的结果都是第5次之后平均每秒吞吐量。为了更像一个典型的java应用;没有采用会导致明显减少差异的线程依附性(thread affinity)和多核隔离(core isolation )技术;

结果:


上述图表的原始数据可以在这里找到

分析:

结果里面真正令我吃惊的是ReentrantReadWriteLock的性能,我没有想到的是,在这样的场景下它在读和少量写之间取得的巨大的平衡性,

我主要的收获:

1、StampedLock 对现存的锁实现有巨大的改进,特别是在读线程越来越多的场景下:

2、StampedLock有一个复杂的API,对于加锁操作,很容易误用其他方法;

3、当只有2个竞争者的时候,Synchronised是一个很好的通用的锁实现;

4、当线程增长能够预估,ReentrantLock是一个很好的通用的锁实现;

5、选择使用ReentrantReadWriteLock时,必须经过小心的适度的测试 ;所有重大的决定,必须在基于测试数据的基础上做决定;

6、无锁的实现比基于锁的算法有更好短吞吐量;

结论:

非常开心能看到无锁技术对基于锁的算法的影响; 乐观锁的策略,实际上就是一个无锁算法技术。

以我的经验看,教学和开发中的无锁算法,不仅能显著改善吞吐量;同时他们也提供更低的延迟。 

时间: 2024-08-01 21:29:19

基于锁的并发算法 vs 无锁的并发算法的相关文章

Java 高并发四:无锁详细介绍_java

在[高并发Java 一] 前言中已经提到了无锁的概念,由于在jdk源码中有大量的无锁应用,所以在这里介绍下无锁. 1 无锁类的原理详解 1.1 CAS CAS算法的过程是这样:它包含3个参数CAS(V,E,N).V表示要更新的变量,E表示预期值,N表示新值.仅当V 值等于E值时,才会将V的值设为N,如果V值和E值不同,则说明已经有其他线程做了更新,则当前线程什么 都不做.最后,CAS返回当前V的真实值.CAS操作是抱着乐观的态度进行的,它总是认为自己可以成功完成 操作.当多个线程同时使用CAS操

使用JAVA实现高并发无锁数据库操作步骤分享_java

1. 并发中如何无锁.一个很简单的思路,把并发转化成为单线程.Java的Disruptor就是一个很好的例子.如果用java的concurrentCollection类去做,原理就是启动一个线程,跑一个Queue,并发的时候,任务压入Queue,线程轮训读取这个Queue,然后一个个顺序执行. 在这个设计模式下,任何并发都会变成了单线程操作,而且速度非常快.现在的node.js, 或者比较普通的ARPG服务端都是这个设计,"大循环"架构.这样,我们原来的系统就有了2个环境:并发环境 +

无锁并不像人们所说的那么好

原文链接,译文连接,译者:梁海舰,校对:李任 注意,我将在这篇文章中说一些关于"无锁"和"无等待"算法的坏话.在我们开始之前,让我来问你一个问题: 你之前有过需要无锁算法来解决问题吗?为什么必须使用无锁算法来解决? 这是一个意味深长的问题,在某种意义上,我们尝试区分哪些问题需要"无锁"或者受益于"无锁"提供的保证,哪些问题使用阻塞解决方案就已经足够了.那么,什么样的问题可以利用无锁算法解决呢? 你会说高竞争下的扩展性?是的,听

无锁数据结构(Lock-Free Data Structures)

原文:无锁数据结构(Lock-Free Data Structures) 一个星期前,我写了关于SQL Server里闩锁(Latches)和自旋锁(Spinlocks)的文章.2个同步原语(synchronization primitives)是用来保护SQL Server里的共享数据结构,例如缓存池里的页(通过闩锁(Latches)),锁管理器哈希表里的锁(通过自旋锁(Spinlock)).接下里你会看到越来越多的全新同步原语(synchronization primitives),即所谓的

C#算法之基于无锁的C#并发队列实现

最近开始学习无锁编程,和传统的基于Lock的算法相比,无锁编程具有其独特的优点,Angel Lucifer 的关于无锁编程一文对此有详细的描述. 无锁编程的目标是在不使用Lock的前提下保证并发过程中共享数据的一致性,其主要的实现基础是CAS 操作,也就是compare_and_swap,通过处理器提供的指令,可以原子地更新共享数据,并同时监测其他线 程的干扰,.Net中的对应实现是InterLocked.CompareExchange函数. 既然不使用Lock,那在无锁编程中要时刻注意的是,代

无锁并发和无等待并发的对比分析

原文地址:作者:rethinkdb  译者:sooerr 校对:方腾飞 有两种非阻塞线程同步算法,即无锁和无等待,这两种算法经常会产生混淆. 在无锁系统中,当任何特定的运算被阻塞的时候,所有CPU可以继续处理其他的运算.换种方式说,在无锁系统中,当给定线程被其他线程阻塞的时候,所有CPU可以不停的继续处理其他工作.无锁算法大大增加系统整体的吞吐量,因为它只偶尔会增加一定的交易延迟.大部分高端数据库系统是基于无锁算法而构造的,以满足不同级别. 相反,无等待算法保证了所有CPU在连续处理有效工作的时

PgSQL · 源码分析 · PG中的无锁算法和原子操作应用一则

原子操作概述 近年来随着服务器上CPU核数的不断增加,无锁算法(Lock Free)越来越广泛的被应用于高并发的系统中.PostgreSQL 做为世界上最高级开源数据库也在9.5时引入了无锁算法.本文先介绍了无锁算法和原子操作在PostgreSQL中的具体实现, 再通过一个Patch来看一下在PostgreSQL中是如何利用它来解决实际的高并发问题的. 无锁算法是利用CPU的原子操作实现的数据结构和算法来解决原来只能用锁才能解决的并发控制问题. 众所周知,在一个并发系统中特别是高并发的场景下,锁

Disruptor(无锁并发框架)-发布

原文:http://blog.codeaholics.org/2011/the-disruptor-lock-free-publishing/ 译者:罗立树 假如你生活在另外一个星球,我们最近开源了一套高性能的基于消息传递的开源框架. 下面我给大家介绍一下如何将消息通过Ring buffer在无锁的情况下进行处理. 在深入介绍之前,可以先快速阅读一下Trish发表的文章,该文章介绍了ring buffer和其工作原理. 这篇文章的要点如下: 1.ring buffer是由一个大数组组成的. 2.

无锁并发框架Disruptor

概述 在逛并发编程网的时候,看到了并发框架Disruptor译文这个系列文章. Martin Fowler在自己网站上写了一篇LMAX架构(译文)的文章,在文章中他介绍了LMAX是一种新型零售金融交易平台,它能够以很低的延迟产生大量交易.这个系统是建立在JVM平台上,其核心是一个业务逻辑处理器,它能够在一个线程里每秒处理6百万订单.业务逻辑处理器完全是运行在内存中,使用事件源驱动方式.业务逻辑处理器的核心是Disruptor. Disruptor它是一个开源的并发框架,能够在无锁的情况下实现网络