/** * Indicate that a non-root node is most recently used. Root node is not managed in usage * list and cannot be evicted. Caller must hold any latch on node. Latch is never released * by this method, even if an exception is thrown. */ void used(final Node node, final ThreadLocalRandom rnd) { // Moving the node in the usage list is expensive for several reasons. First is the // rapid rate at which shared memory is written to. This creates memory access // contention between CPU cores. Second is the garbage collector. The G1 collector in // particular appears to be very sensitive to old generation objects being shuffled // around too much. Finally, latch acquisition itself can cause contention. If the node // is popular, it will get more chances to be identified as most recently used. This // strategy works well enough because cache eviction is always a best-guess approach. if ((rnd.nextLong() & mUsedRate) == 0 && tryAcquireExclusive()) { doUsed(node); } }
/** * Indicate that a non-root node is most recently used. Root node is not managed in usage * list and cannot be evicted. Caller must hold any latch on node. Latch is never released * by this method, even if an exception is thrown. */ void used(final Node node, final ThreadLocalRandom rnd) { // Moving the node in the usage list is expensive for several reasons. First is the // rapid rate at which shared memory is written to. This creates memory access // contention between CPU cores. Second is the garbage collector. The G1 collector in // particular appears to be very sensitive to old generation objects being shuffled // around too much. Finally, latch acquisition itself can cause contention. If the node // is popular, it will get more chances to be identified as most recently used. This // strategy works well enough because cache eviction is always a best-guess approach. if ((rnd.nextLong() & mUsedRate) == 0 && tryAcquireExclusive()) { doUsed(node); } }