Unsuccessful behavior of StampedLock.unlock (long)?

I think the strange behavior of StampedLock . Here are the main problematic lines of code:

StampedLock lock = new StampedLock(); long stamp1 = lock.readLock(); System.out.printf("Read lock count: %d%n", lock.getReadLockCount()); lock.unlock(stamp1 + 2); System.out.printf("Read lock count: %d%n", lock.getReadLockCount()); 

Strange behavior is how to unlock a β€œvalid” invalid print stamp. Does it seem right to you?


For reference: full code:

 public class StampedLockExample { static StampedLock lock = new StampedLock(); static void println(String message, Object... args) { System.out.printf(message, args); System.out.println(); } static void printReadLockCount() { println("Lock count=%d", lock.getReadLockCount()); } static long tryReadLock() { long stamp = lock.tryReadLock(); println("Gets read lock (%d)", stamp); printReadLockCount(); return stamp; } static long tryWriteLock() { long stamp = lock.tryWriteLock(); println("Gets write lock (%d)", stamp); return stamp; } static long tryConvertToReadLock(long stamp) { long newOne = lock.tryConvertToReadLock(stamp); println("Gets read lock (%d -> %d)", stamp, newOne); printReadLockCount(); return newOne; } static void tryUnlock(long stamp) { try { lock.unlock(stamp); println("Unlock (%d) successfully", stamp); } catch (IllegalMonitorStateException e) { println("Unlock (%d) failed", stamp); } printReadLockCount(); } public static void main(String[] args) { println("%n--- Gets two read locks ---"); long stamp1 = tryReadLock(); long stamp2 = tryReadLock(); long min = Math.min(stamp1, stamp2); long max = Math.max(stamp1, stamp2); println("%n--- Tries unlock (-1 / +2 / +4) ---"); tryUnlock(min - 1); tryUnlock(max + 2); tryUnlock(max + 4); println("%n--- Gets write lock ---"); long stamp3 = tryWriteLock(); println("%n--- Tries unlock (-1 / +1) ---"); tryUnlock(stamp3 - 1); tryUnlock(stamp3 + 1); println("%n--- Tries write > read conversion ---"); long stamp4 = tryConvertToReadLock(stamp3); println("%n--- Tries unlock last write stamp (-1 / 0 / +1) ---"); tryUnlock(stamp3 - 1); tryUnlock(stamp3); tryUnlock(stamp3 + 1); println("%n--- Tries unlock (-1 / +1) ---"); tryUnlock(stamp4 - 1); tryUnlock(stamp4 + 1); } } 

Output:

 --- Gets two read locks --- Gets read lock (257) Lock count=1 Gets read lock (258) Lock count=2 --- Tries unlock (-1 / +2 / +4) --- Unlock (256) failed Lock count=2 Unlock (260) successfully Lock count=1 Unlock (262) successfully Lock count=0 --- Gets write lock --- Gets write lock (384) --- Tries unlock (-1 / +1) --- Unlock (383) failed Lock count=0 Unlock (385) failed Lock count=0 --- Tries write > read conversion --- Gets read lock (384 -> 513) Lock count=1 --- Tries unlock last write stamp (-1 / 0 / +1) --- Unlock (383) failed Lock count=1 Unlock (384) failed Lock count=1 Unlock (385) failed Lock count=1 --- Tries unlock (-1 / +1) --- Unlock (512) failed Lock count=1 Unlock (514) successfully Lock count=0 
+6
source share
2 answers

Short answer:

Adding two to the stamp changes part of it, which does not require a check in read-mode locks.

Long answer:

The stamp contains two pieces of information: the serial number of the state and the number of readers. The status number is stored in the first 57 bits of the stamp, and the number of readers is stored in the last 7 bits. Therefore, when you add 2 to the brand, you change the number of readers from 1 to 3 and leave the status number unchanged. Since StampedLock was received only in read mode, only the status number is checked, and the number of readers is ignored. This makes sense, as read locks should be able to unlock in any order.

For example: a read stamp is obtained from an existing StampedLock and has a number of states 4 and a number of readers 1. A second read stamp is obtained from the same StampedLock and has a number of states 4 and a number of readers from 2. Note that the state numbers of the brands are the same since the state StampedLock has not changed between the acquisition of stamps. The first print mark is used in unlocking. The status number of the first stamp (4) corresponds to the status number of StampedLock (4), so it’s fine. The number of readers of the first stamp (1) does not match the number of readers of StampedLock (2), but this does not matter, since read locks must be able to unlock in any order. Thus, the unlock failed.

Please note that StampedLocks were designed for high-performance read / write locks for internal utilities, and not in order to withstand malicious coding, therefore acting within their intended boundaries. I really think Javadoc unlock () is misleading.

+4
source

key part from javadocs:

Stamps use finite representations and are not cryptographically secure (i.e. valid printing may be valid).

This means that you should consider them as opaque values ​​and not try to modify them in any way.

It is possible that one guesses essentially what your arrhythmias do -1, +2, +4. This is not easy to guess, but easy to do if you have a good starting point for guessing, for example, the previous token.

In addition, StampedLock.validate (long) :

Calling this method with a value not obtained from tryOptimisticRead (), or the locking method for this locking, has no specific effect or result.

In other words: any token value that is not obtained directly from one of the Lock methods is not only invalid, but also entails undefined behavior.

+2
source

Source: https://habr.com/ru/post/988523/


All Articles