Dictionary for locking on unique identifiers without leaking memory
ItemLock._ItemLock is not used anywhere. Also, as a side note, I'm not a fan of using _NamesLikeThis for public items
Using a single lock may not be the best idea performance-wise (though heavily scenario-dependent). Consider using CuncurrentDictionary (which of course brings all sorts of new propblems, but this is how concurrency works). Also, you may consider using a ReadWriteLockSlim, it might be more performant in some scenarios
ReleaseLock is not safe if not matched by a Lock call. Which might happen for example in case of a ThreadAbort. An ugly, but widespread way of dealing with it is placing the critical code to a finally block. This article from the SQL Server people might also be of interest: https://docs.microsoft.com/en-us/dotnet/framework/performance/reliability-best-practices