Replaced synchronized with ReentrantReadWriteLock

This removes all synchronized statements in favor of a
```ReentrantReadWriteLock```. This allows read operations to not block
each other, but write operations to block everything (*the way
synchronized was working previously*).

With the addition of a simple ```contains()``` method, it is now super
cheap to check if an image exists in the cache.

Added unit tests for the new contains() method.