2014-09-29 79 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)來檢查郵票是否有效。