2015-10-26 14 views
9

ReadWriteLock hạ cấp được cho phép bởi ReentrantReadWriteLock thực hiện (tryLock() từ ví dụ dưới đây luôn luôn trả true):Tại sao không được phép nâng cấp ReadWriteLock?

void downgrade(final ReadWriteLock readWriteLock) { 
    boolean downgraded = false; 
    readWriteLock.writeLock().lock(); 
    try { 
     // Always true, as we already hold a W lock. 
     final boolean readLockAcquired = readWriteLock.readLock().tryLock(); 
     if (readLockAcquired) { 
      // Now holding both a R and a W lock. 
      assert ((ReentrantReadWriteLock) readWriteLock).getReadHoldCount() == 1; 
      assert ((ReentrantReadWriteLock) readWriteLock).getWriteHoldCount() == 1; 

      readWriteLock.writeLock().unlock(); 
      downgraded = true; 
      try { 
       // Now do some work with only a R lock held 
      } finally { 
       readWriteLock.readLock().unlock(); 

       assert ((ReentrantReadWriteLock) readWriteLock).getReadHoldCount() == 0; 
       assert ((ReentrantReadWriteLock) readWriteLock).getWriteHoldCount() == 0; 
      } 
     } 
    } finally { 
     if (!downgraded) { 
      // Never (we were holding a W lock while trying a R lock). 
      readWriteLock.writeLock().unlock(); 
     } 
     assert ((ReentrantReadWriteLock) readWriteLock).getReadHoldCount() == 0; 
     assert ((ReentrantReadWriteLock) readWriteLock).getWriteHoldCount() == 0; 
    } 
} 

ý tưởng đằng sau không cho phép nâng cấp khóa một cách tương tự là gì? Phương pháp tryLock() cho một Viết khóa dưới đây một cách an toàn có thể trở lại true w/rủi ro oa cho một bế tắc trong sự vắng mặt của chủ đề khác cầm một đọc khóa:

void upgrade(final ReadWriteLock readWriteLock) { 
    readWriteLock.readLock().lock(); 
    try { 
     // Always false: lock upgrade is not allowed 
     final boolean writeLockAcquired = readWriteLock.writeLock().tryLock(); 
     // ... 
    } finally { 
     readWriteLock.readLock().unlock(); 
    } 
} 
+4

Nếu bạn sử dụng Java 8, bạn có thể muốn có một cái nhìn tại 'StampedLock'. Nói chung, bạn có thể muốn xem [video này] (https://www.youtube.com/watch?v=Q_0_1mKTlnY) từ Angelika Langer. Đổ chuông, phải không? ;) – fge

Trả lời

2

Trước tiên, hãy lưu ý rằng nâng cấp và hạ cấp là không tương đương về mặt phức tạp ngữ nghĩa đối với ReadWriteLock s.

Bạn không cần phải chống lại tranh chấp để hoàn tất giao dịch hạ cấp vì bạn đã nắm giữ các đặc quyền leo thang nhất trên khóa và bởi vì bạn được đảm bảo là chuỗi duy nhất hiện đang hạ cấp. Điều tương tự cũng không đúng đối với việc nâng cấp, do đó, cơ chế nâng cấp tự nhiên cần phải phức tạp hơn (hoặc thông minh hơn nhiều).

Để có thể sử dụng được, cơ chế nâng cấp cần phải ngăn chặn deadlocks trong trường hợp hai chủ đề đọc đồng thời cố nâng cấp (hoặc cụ thể cho ReentrantReadWriteLock, trong trường hợp một chuỗi đọc duy nhất giữ nhiều khóa đọc cố nâng cấp). Ngoài ra, cơ chế cần phải chỉ định cách xử lý yêu cầu nâng cấp không thành công (khóa đọc của nó có bị vô hiệu hóa) và điều đó thậm chí còn ít tầm thường hơn.

Như bạn có thể thấy bây giờ, việc xử lý hoàn toàn những vấn đề này trong ReentrantReadWriteLock là bất tiện khi nói ít nhất (vẫn còn, đây là những gì .NET's ReaderWriterLock cố gắng và tôi nghĩ thực sự thành công để làm). Tôi đoán rằng trong khi final boolean writeLockAcquired = readWriteLock.writeLock().tryLock(); có thể đã được thực hiện để thành công trong một số trường hợp tầm thường, việc nâng cấp vẫn sẽ không đủ tốt để sử dụng chung - dưới ganh đua đủ nặng, nếu bạn mất cuộc đua viết khóa, bạn đang ở trong cùng một chiếc thuyền như thể bạn mở khóa khóa đọc và cố gắng để có được khóa viết (để lại cơ hội cho người khác lẻn vào và lấy khóa viết ở giữa).

Cách tốt nhất để cung cấp khả năng nâng cấp khóa là chỉ cho phép một chuỗi duy nhất để cố gắng nâng cấp - đây là những gì ReentrantReadWriteUpdateLock làm hoặc những gì .NET's ReaderWriterLockSlim làm. Tuy nhiên tôi vẫn muốn giới thiệu Java 8 của StampedLock như:

  • dưới tranh thấp lạc quan của nó đọc là nhanh hơn nhiều so với sử dụng đọc ổ khóa
  • API của nó là ít hạn chế về việc nâng cấp (từ đọc lạc quan để đọc khóa để viết khóa)
  • nỗ lực khác nhau của tôi để tạo ra một chuẩn mực JMH thực tế nơi một trong những ổ khóa tương tự khác đánh bại nó đã hầu như luôn luôn thất bại
Các vấn đề liên quan