The lock taken to move assets to the front of the LRU list protects only that particular node of the list. This is insufficient to prevent race conditions.
Given a list:
| SENTINEL <-> A <-> B <-> C
|
To remove item B, I don't just modify B, I also modify A and C, to redirect their links. So a race exists between two threads that try to move consecutive items to the front at the same time.
Furthermore, a race exists between two threads that try to move *any* item, because moving to the front of the list modifies the sentinel node.
To properly protect the list from race conditions, ALL modifications to the list need to be serialized. The easiest solution would most likely be to lock the sentinel node itself.