`
zwt2001267
  • 浏览: 445952 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

与基于锁的方案相比稍显复杂非阻塞算法

阅读更多

阻塞算法介绍 

  目前,很多关于并发算法的研究都聚集在非阻塞算法(nonblocking algorithms)上,这种算法使用低层原子化的机器指令取代锁,比如compare-and-swap,从而保证数据在兵法访问下的一致性。非阻塞算法广泛应用于操作系统和JVM的线程和进程调度、垃圾回收以及实现所和其他的并发数据结构。 

  与基于锁的方案相比,非阻塞算法的设计和实现都要复杂一些,但是它们在可伸缩性和活跃度上占有很大的优势。因为非阻塞算法可以让多个线程在竞争相同资源时不会发生阻塞,所以它能在更精化的层面上调整粒度,并能大大减少开销。进一步而言,它们对死锁和其他活跃度问题具有免疫性。基于锁的算法中,如果一个线程在持有锁的时候休眠,或者停滞不前,那么其它线程就都不能前进了,而非阻塞算法不会受到单个线程失败的影响。在Java 5.0中,使用atomic variable classes,比如AtomicInteger和AtomicReference,能够高效构建非阻赛算法。 

  非阻塞算法的关键思想就是CAS,CAS是compare and set的缩写,也常被称为lock-free或者wait-free,通过把compare和set两个操作原子化,使得不需要使用锁,但是能够解决并发中的资源争用问题。由于CAS常常是一个回退算法+外循环,所以又被称为spin-lock。由于CAS没有使用锁,线程持续执行,又称为非阻塞算法(non-blocking)。术语不统一,有细微差别,但都差不多表示同一个东西,我都列在这里,方便大家理解。 

  非阻塞算法的实现通常包括如下部分:外循环、回退、CAS操作。伪码如下: 

  WHILE (TRUE) // 外循环 

  { 

  准备数据 

  IF CAS_OP() == SUCCESS THEN 

  BREAK; 

  END IF 

  } 

  非阻塞算法思想在关系数据库开发中的应用 

  有人说,非阻塞算法这种技术底层框架提供,不需要了解,其实不然,CAS思想可以应用任何地方,包括数据结构、服务接口、数据库应用等等。我这篇文章要讲的内容就是在关系数据库应用中使用CAS思想。 

  关系数据库数据库提供了"update T set FState = xx where FState = xx",执行这样的SQL,会返回一个更新行数,在jdbc或者odbc或者ADO .NET中都可以获得更新行数。上面的SQL,如果更新行数>0,则是更新成功,否则是没有进行任何更新,这是很典型的CAS。可以说,关系数据库 原生支持CAS。 

  关系数据库中采用事务来确保并发时的原子性,事务实际上就是一种“锁”。关系数据库中通常有排他锁和共享锁的概念,这有点类似于Java中ReadWriteLock。需要更新数据时,我们通常使用到关系数据库的排他锁,在Oracle中需要使用SELECT … FOR UPDATE,在Microsoft SQL Server中,使用lock hints。 

  我们举两个例子描述CAS在关系数据开发中的应用。 

  例一 读取并更新 

  传统使用数据库事务的实现 

  public long transactionGetAndIncrement(Connection conn, long id) throws Exception { 

  // 为了简化,不适用try...finally的方式释放Statement和ResultSet等资源 

  conn.setAutoCommit(false); 

  Long expect = null; 

  // 读取当前值 

  String sql = "SELECT FValue FROM T_TEST_CAS T WHERE FID = ? FOR UPDATE"; 

  PreparedStatement stmt = conn.prepareStatement(sql); 

  stmt.setLong(1, id); 

  ResultSet rs = stmt.executeQuery(); 

  if (rs.next()) expect = rs.getLong(1); 

  rs.close(); 

  stmt.close(); 

  if (expect == null) { 

  conn.commit(); 

  throw new Exception("id '" + id + "' invalid."); 

  } 

  // 更新加1 

  sql = "UPDATE T_TEST_CAS SET FValue = ? WHERE FID = ?"; 

  stmt = conn.prepareStatement(sql); 

  stmt.setLong(1, expect.longValue() + 1); 

  stmt.setLong(2, id); 

  int updateCount = stmt.executeUpdate(); 

  stmt.close(); 

  if (updateCount == 0) throw new Exception("id '" + id + "' invalid."); 

  conn.commit(); 

  return expect.longValue(); 

  } 

  CAS方式的实现 

  // 为了简化,不适用try...finally的方式释放Statement和ResultSet等资源 

  public long casGetAndIncrement(Connection conn, long id) throws Exception { 

  for (;;) { // 外循环 

  Long expect = null; 

  String sql = "SELECT FValue FROM T_TEST_CAS T WHERE FID = ?"; 

  PreparedStatement stmt = conn.prepareStatement(sql); 

  stmt.setLong(1, id); 

  ResultSet rs = stmt.executeQuery(); 

  if (rs.next()) { 

  expect = rs.getLong(1); 

  } 

  rs.close(); 

  stmt.close(); 

  if (expect == null) throw new Exception("id '" + id + "' invalid."); 

  // 比较更新 

  sql = "UPDATE T_TEST_CAS SET FValue = ? WHERE FID = ? AND FValue = ?"; 

  stmt = conn.prepareStatement(sql); 

  stmt.setLong(1, expect.longValue() + 1); 

  stmt.setLong(2, id); 

  stmt.setLong(3, expect.longValue()); 

  int updateCount = stmt.executeUpdate(); 

  stmt.close(); 

  // 如果updateCount > 0,更新成功,返回退出循环,否则回退重来 

  if (updateCount > 0) return expect.longValue(); 

  } 

  } 

  例二 使用CAS读取并且删除数据表中最小的值的一行 

  public Long compareAndDelete 

  (Connection conn) throws Exception { 

  for (;;) { //外循环 

  Long minValue = null; 

  // 读取最小值 

  String sql = "SELECT MIN(FVALUE) FROM T"; 

  PreparedStatement stmt = conn.prepareStatement(sql); 

  ResultSet rs = stmt.executeQuery(); 

  if (rs.next()) minValue = rs.getLong(1); 

  rs.close(); 

  stmt.close(); 

  if (minValue == null) return null; 

  // 比较删除 

  sql = "DELETE FROM T WHERE FVALUE = ?"; 

  stmt = conn.prepareStatement(sql); 

  stmt.setLong(1, minValue.longValue()); 

  int updateCount = stmt.executeUpdate(); 

  stmt.close(); 

  // 如果updateCount > 0, 

  删除成功,返回退出循环,否则回退重来 

  if (updateCount > 0) return minValue; 

  } 

  } 

  在例二的场景中,使用事务还不好实现,因为Oracle中使用了MIN函数就不能使用 FOR UPDATE。 

  性能比较 

  在Oracle 10g上作测试,使用CAS的方式测试例一,在10个线程并发测试跑1000次,CAS的方式会比使用事务的方式快10~20。如果加大线程跑并发,CAS的性能逐渐下降,也符合CAS算法在激烈竞争下性能不高的场景。但是实际环境中,很少会在同一点上存在激烈竞争,所以采用CAS的方式会比使用事务的方式效率更高。 

  总结 

  1、在关系数据库开发中使用非阻塞算法,由于非阻塞算法自身保证原子性,所以不能在嵌套在事务中使用。 

  2、使用非阻塞算法不使用事务,不适用悲观的独占锁,不存在激烈竞争的情况下,性能比采用事务的方式性能更好。 

  3、非阻塞关系数据库算法,适用于分布式工作流系统、后台调度程序等场景,能够在并发和集群环境下工作良好。 

  4、非阻塞算法的思想不单可用于系统底层框架,而且适用于任何地方。

分享到:
评论

相关推荐

    蚁群算法在路由选择中的应用

    通过模拟对比,该蚁群算法相比于传统RWA算法,能更好地适应网络条件变化,动态调整路由选择,降低突发阻塞概率,提高网络的整体性能。这种方法的引入,不仅提高了OBS网络的资源利用率,还增强了网络的鲁棒性,有助于...

    一种基于FPGA并行流水线的FIR滤波器设计方案

    与传统算法相比,分布式算法能够在较低的硬件资源消耗下实现高速的运算,非常适合FPGA内部的并行架构。 #### 关键技术:分布式算法 分布式算法的核心思想是在乘法操作之前先执行加法操作,即将输入数据的每一位...

    基于FPGA的LED大屏幕控制系统的设计与实现.pdf

    由于传统基于SDRAM的乒乓式缓存方案存在数据读写操作复杂或数据结构调整局限性大的问题,本文提出了优化的方案。乒乓式缓存是一种双缓冲技术,可以用于避免数据处理中的阻塞现象,提高系统的效率和响应速度。优化...

    多线程面试题及处理方案和详解

    与`synchronized`相比,它提供了更多的功能和更好的灵活性。 - **核心组件**: - **Sync**:抽象同步器,继承自`AbstractQueuedSynchronizer`,负责管理锁的状态和排队等待的线程。 - **Condition**:条件变量,...

    跳槽涨薪涨薪必备精选面试题.pdf

    Netty是高性能的网络通信框架,与Tomcat主要区别在于它是异步非阻塞的,适合高并发场景。 Netty的线程模型包括BossGroup和WorkerGroup,BossGroup负责接收连接,WorkerGroup处理I/O事件。 Netty的高性能体现在零...

    paxos的开源实现

    这种机制允许复制的对象控制其客户端的执行流程,从而提供了阻塞和非阻塞性方法调用,可用于实现更丰富的同步构造。这意味着开发者可以更灵活地设计系统的行为,同时确保在分布式环境中的一致性和安全性。 #### ...

    60道关于Redis的常见面试题.pdf

    - **高性能**:采用单线程非阻塞I/O模型,能够快速响应读写请求。 - **丰富的数据结构**:支持字符串(String)、哈希(Hash)、列表(List)、集合(Set)及有序集合(Sorted Set)等。 - **持久化**:提供RDB...

    《计算机操作系统》期末复习指导

    与分区式相比,不需移动作业;与多重分区比,无零星碎片产生。 缺点: •要处理页面中断、缺页中断处理等,系统开销较大; •有可能产生“抖动”; •地址变换机构复杂,为提高速度采用硬件实现,...

    NGINX的功能介绍

    3. **优秀的并发处理能力**:NGINX采用异步非阻塞的模型来处理请求,这意味着它可以同时处理大量的连接而不会导致资源过度消耗。 #### 二、NGINX的工作原理 1. **进程模型**:NGINX在启动时会创建一个主进程...

    大厂的Android面试题.pdf

    - **加密算法**:RSA等非对称加密算法用于密钥交换;对称加密算法如AES用于数据加密。 - **MVP模式**:MVP模式将视图与业务逻辑解耦,提高代码可维护性。 - **Handler实现机制**:Handler通过Looper和Message...

    利用Petri网设计无阻塞监督者的集成控制方法

    与文献中已报道的死锁控制策略相比,所提出的算法能够实现一个具有简单结构和高计算效率的非阻塞控制的G系统。最后,通过一个基准G系统的例子,证明了新方法的有效性。 Petri网是由德国计算机科学家Carl Adam Petri...

    FPGA例程讲解笔记——经典实用

    与C语言相比,它更注重于描述硬件的行为而非算法流程。 **区别**: - **数据类型**:VerilogHDL中有wire、reg等数据类型,而C语言中主要是int、float等。 - **执行方式**:VerilogHDL是并发执行的,而C语言是顺序...

    稍微有点难度的10道java面试题,你会几道?

    - **非阻塞I/O**:支持异步处理,提高高并发场景下的处理能力。 - **注解支持**:简化Servlet、过滤器和监听器的配置。 - **Servlet容器初始化参数**:允许在部署描述符中配置Servlet容器的行为。 - **HTTP升级机制*...

    skynet-master

    服务之间通过发送消息来协同工作,这种异步非阻塞的通信方式提高了系统整体的响应速度。Skynet框架还包含了一个内置的服务发现机制,使得服务能够动态地找到并与其他服务交互。 Lua被用作默认的脚本语言,是因为其...

    实战Nginx~~~

    1. **高性能**:Nginx使用了异步非阻塞的事件驱动架构,能够高效地处理大量的并发连接。相比之下,传统的Web服务器如Apache通常采用基于进程或线程的模型来处理请求,这在高并发场景下可能导致性能瓶颈。 2. **低...

    海风教育(14问).pdf

    在Node.js中,一个实例通常代表一个进程,由于Node.js是单线程的,它通过事件循环(Event Loop)机制来实现异步非阻塞I/O。 12. DFS深度优先搜索:深度优先搜索(DFS)是一种用于遍历或搜索树或图的算法。它沿着树...

    EAalo:在数据中心网络中无需先验知识的增强型同流调度

    二是它假设网络是理想的非阻塞型,即流量平衡且无过载的情况。 本文针对Aalo方案存在的问题,提出了增强型同流调度EAalo。EAalo对Aalo有三个主要的改进点:第一个改进点是实现了对每个流的带宽强制执行,这可以帮助...

Global site tag (gtag.js) - Google Analytics