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

2008-02-23 07:43:46来源:互联网 阅读 ()

新老客户大回馈,云服务器低至5折

  非阻塞算法介绍

  近年来,很多关于并发算法的研究都聚集在非阻塞算法(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在关系数据研发中的应用。

  例一 读取并更新

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

标签:

版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有

上一篇: MySQL数据库对文档操作的封装

下一篇: MYSQL的master/slave数据同步配置

  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();
  }
  }