technically, this allows for a race condition; should probably use a ConcurrentHashMap