StampedLock#tryOptimisticRead()实现

时间:2018-05-03 15:32:47

标签: java multithreading concurrency

我正在使用 StampedLock 实现缓存读取或加载方法,我想知道我是否可以更好地调整javadoc中的示例。

作者Doug Lea给出了一个'乐观读'示例和一个'升级读锁定写锁'的例子,但在我的用例中我想要同时做两件事。

public String getConverted(String input) {

    String customised = null;
    long stamp = 0L;

    while (customised == null) {
        if (!lock.validate(stamp)) {
            stamp = lock.tryOptimisticRead();
        }
        customised = cached.get(input);

        // if the lock was valid we can trust the value of customised
        if (lock.validate(stamp) && customised == null) {
            long writeStamp = 0L;
            try {
                while (customised == null) {
                    writeStamp = lock.tryConvertToWriteLock(stamp);
                    if (writeStamp != 0L) {
                        stamp = writeStamp;
                        customised = convertToCustom(input);
                        cached.put(input, customised);
                    } else {

                        // so what do we do here (line 15)?

                    }
                }
            } finally {
                lock.unlock(stamp);
            }
        } else {
            // if the lock was invalid, customised could be anything, so:
            customised = null;

            // and what do we do here (line 25)?
        }
    }

    return customised;
}

因此算法中有两点需要做点什么 - 在两种情况下都是:

  1. 获取硬锁 - 在第15行:

                        lock.unlockRead(stamp);
                        stamp = lock.writeLock();
    

    并在第25行:

                        stamp = lock.readLock();
    
  2. 或者是什么?

                        Thread.sleep(25); 
    
  3. 这对我来说并没有削减它 - 当然StampedLock可以更好地管理这个线程上的阻塞!

    但是怎么样?如果我只是致电readLock()writeLock(),那么我会在StampedLock#tryOptimisticRead()StampedLock#tryConvertToWriteLock()内放弃经过良好编码和测试的排队算法。

    或者这些方法背后的逻辑是否因为失败一次而被没收?

1 个答案:

答案 0 :(得分:2)

您可以查看以下方法以供参考。

tryConvertToWriteLock和tryOptimisticRead中没有排队机制。

  

方法tryOptimisticRead()仅在锁定时返回非零标记   目前未处于写入模式。方法验证(long)返回   如果在获取a之后未在写入模式下获取锁定,则为true   给予邮票。这种模式可以被认为是一个非常弱的版本   读锁定,可以随时由作者打破。指某东西的用途   短只读代码段的乐观模式通常会减少   争用并提高吞吐量。但是,它的使用本质上是有用的   脆弱。乐观的阅读部分应该只读取字段并保持   它们在局部变量中供以后验证后使用。字段读取   而在乐观模式下可能会非常不一致,因此适用   只有当您熟悉数据表示才能检查时   一致性和/或反复调用方法validate()。例如,   首次阅读对象时通常需要执行此类步骤   数组引用,然后访问其中一个字段,元素或   方法

另外,我喜欢你检查乐观锁定有效性的控制流程,如果你发现它是无效的,那么就获得锁定,因为它避免了" else"代码中使用的块。

tryConvertToWriteLock 的类似代码流。

private final StampedLock sl = new StampedLock(); 

    /**


    * This method is to show the feature of tryOptimisticRead() method  
    */ 
      public double getTotalRevenueOptimisticRead() {  
        long stamp = sl.tryOptimisticRead();  
        double balance = this.totalRevenue;
        boolean lockAcquired = false;   
        //calling validate(stamp) method to ensure that stamp is valid, if not then acquiring the read lock  
        if (!sl.validate(stamp)){
          lockAcquired = true;   
          LOG.info("stamp for tryOptimisticRead() is not valid now, so acquiring the read lock");   
          stamp = sl.readLock();  
        }     
        try {    
          balance = this.totalRevenue;   
        } finally {
          if(lockAcquired){
             sl.unlockRead(stamp); 
          }    
        }  
        return balance; 
      } 



/**  
* This method is to show the feature of tryConvertToWriteLock() method  
*/ 
  public double getStateTaxReturnUisngConvertToWriteLock(TaxPayer taxPayer) { 
    double incomeTaxRetunAmount = taxPayer.getTaxAmount() * 5/100;  
    long stamp = sl.readLock();
    boolean lockAcquired = false;     
    //Trying to upgrade the lock from read to write  
    stamp = sl.tryConvertToWriteLock(stamp);    
    //Checking if tryConvertToWriteLock got success otherwise call writeLock method  
    if(stamp == 0L){   
      LOG.info("stamp is zero for tryConvertToWriteLock(), so acquiring the write lock");   
      stamp = sl.writeLock();
      lockAcquired = true;  
    }    
    try {   
      this.totalRevenue -= incomeTaxRetunAmount;  
    } finally {
      if(lockAcquired){
         sl.unlockWrite(stamp);
      }   
    }  
    return incomeTaxRetunAmount; 
  }