2014-09-29 44 views
12

我正在研究Java代码,我需要在其中实现线程。我正在浏览JAVA 8 API,并开始了解印章。任何人都可以告诉我为什么要在多线程中使用StampedLock?什么是Java中的StampedLock?

在此先感谢。

+2

什么是_normal multithreading_? – Keppil 2014-09-29 07:10:27

+0

@ SimY4我刚刚阅读了关于doc中的加盖锁。然后我搜索了一下。但是我没有弄清楚为什么我们应该使用它。使用Stamped锁必须有一些优点,这就是为什么Oracle在java 8中引入它的原因。 – Mohit 2014-09-29 07:16:14

+0

@Keppil我编辑了我的问题。谢谢你纠正我。 – Mohit 2014-09-29 07:17:22

回答

14

StampedLock是使用ReadWriteLock(由ReentrantReadWriteLock实现)的替代方案。 StampedLock和的ReentrantReadWriteLock之间的主要区别是:

  • StampedLocks允许读操作的乐观锁定
  • ReentrantLocks是折返(StampedLocks都没有)

所以,如果你有,你有竞争的情景(否则你不妨使用​​或简单的Lock)和比作者更多的读者,使用StampedLock可以显着提高性能。

但是,您应该在跳到结论之前根据您的特定用例来衡量性能。

Heinz Kabutz写了关于StampedLocks in his newsletter和他也作了a presentation about performance

+0

谢谢,现在我知道我可以使用它的情况,并清楚了解它。 – Mohit 2014-09-29 13:47:24

+0

@Mohit,点击链接以更好地理解StampedLock:https://dzone.com/articles/a-look-at-stampedlock – Roshan 2017-10-07 16:34:14

+0

Heinz的文章用一个简短的例子完美地解释了所有的同步机制。谢谢! – 2018-02-17 14:00:35

5

java.util.concurrent.locks.StampedLock的API文档说:

StampedLocks设计用作线程安全组件的开发内部工具。他们的使用依赖于他们所保护的数据,对象和方法的内部属性的知识。它们不是可重入的,因此锁定的机构不应该调用其他可能尝试重新获取锁定的未知方法(尽管您可以将戳记传递给可以使用或转换它的其他方法)。读取锁定模式的使用依赖于相关的代码段是无副作用的。未经验证的乐观阅读部分不能调用未知的方法来容忍潜在的不一致。邮票使用有限的表示,并且不具有密码安全性(即,有效的邮票可能是可猜测的)。在连续运行一年后(不止一年),印花值可能会回收。没有使用或验证时间长于此期限的图章可能无法正确验证。 StampedLocks是可序列化的,但总是反序列化到初始解锁状态,所以它们对远程锁定没有用处。

例如, -

class Point { 
    private double x, y; 
    private final StampedLock sl = new StampedLock(); 

    void move(double deltaX, double deltaY) { // an exclusively locked method 
    long stamp = sl.writeLock(); 
    try { 
     x += deltaX; 
     y += deltaY; 
    } finally { 
     sl.unlockWrite(stamp); 
    } 
    } 

    double distanceFromOrigin() { // A read-only method 
    long stamp = sl.tryOptimisticRead(); 
    double currentX = x, currentY = y; 
    if (!sl.validate(stamp)) { 
     stamp = sl.readLock(); 
     try { 
      currentX = x; 
      currentY = y; 
     } finally { 
      sl.unlockRead(stamp); 
     } 
    } 
    return Math.sqrt(currentX * currentX + currentY * currentY); 
    } 

    void moveIfAtOrigin(double newX, double newY) { // upgrade 
    // Could instead start with optimistic, not read mode 
    long stamp = sl.readLock(); 
    try { 
     while (x == 0.0 && y == 0.0) { 
     long ws = sl.tryConvertToWriteLock(stamp); 
     if (ws != 0L) { 
      stamp = ws; 
      x = newX; 
      y = newY; 
      break; 
     } 
     else { 
      sl.unlockRead(stamp); 
      stamp = sl.writeLock(); 
     } 
     } 
    } finally { 
     sl.unlock(stamp); 
    } 
    } 
} 
1

StampedLock支持读写锁定。与ReadWriteLock相反,StampedLock的锁定方法返回一个由长整型值表示的图章。您可以使用这些印​​章释放锁或检查锁是否仍然有效。另外加盖的锁支持另一种称为乐观锁的锁模式。

ExecutorService executor = Executors.newFixedThreadPool(2); 
     Map<String, String> map = new HashMap<>(); 
     StampedLock lock = new StampedLock(); 

     executor.submit(() -> { 
      long stamp = lock.writeLock(); 
      try { 
       Thread.sleep(100); 
       map.put("test", "INDIA"); 
      } catch (Exception e) { 
      } finally { 
       lock.unlockWrite(stamp); 
      } 
     }); 

     Runnable readTask =() -> { 
      long stamp = lock.readLock(); 
      try { 
       System.out.println(map.get("test")); 
       Thread.sleep(100); 
      } catch (Exception e) { 
      } finally { 
       lock.unlockRead(stamp); 
      } 
     }; 

     executor.submit(readTask); 
     executor.submit(readTask); 

获取的读取或经由readLock()或writeLock(写锁定)返回稍后用于内的最后块解锁邮票。请记住,加盖的锁不会实现重入特性。每次锁定调用都会返回一个新的戳记,并在没有锁定的情况下阻止,即使同一个线程已经拥有一个锁定。所以你必须特别注意不要陷入僵局。

executor.submit(() -> { 
      long stamp = lock.tryOptimisticRead(); 
      try { 
       System.out.println("Optimistic Lock Valid: " + lock.validate(stamp)); 
       Thread.sleep(100); 
       System.out.println("Optimistic Lock Valid: " + lock.validate(stamp)); 
       Thread.sleep(1000); 
       System.out.println("Optimistic Lock Valid: " + lock.validate(stamp)); 
      } catch (Exception e) { 
      } finally { 
       lock.unlock(stamp); 
      } 
     }); 

     executor.submit(() -> { 
      long stamp = lock.writeLock(); 
      try { 
       System.out.println("Write Lock acquired"); 
       Thread.sleep(100); 
      } catch (Exception e) { 
      } finally { 
       lock.unlock(stamp); 
       System.out.println("Write done"); 
      } 
     }); 

乐观的读取锁是通过调用tryOptimisticRead(),它总是返回邮票没有如果锁是实际可用阻止当前线程,不管收购。如果已经有写锁定激活,则返回的标记等于零。您可以随时通过调用lock.validate(stamp)来检查邮票是否有效。