A strong answer
Use a hash map from key to node and a doubly linked list ordered by recency. A lookup uses the map to find a node, then unlinks and moves it to the most-recent end. Insertion updates or creates a node; if capacity is exceeded, remove the least-recent node and delete its key from the map. With a suitable hash table, each operation is expected O(1).
Sentinel head and tail nodes can simplify boundary updates. I would define whether updating an existing key counts as recent use, what capacity zero means, and whether get mutates recency. The map and list must remain consistent if allocation or a concurrent operation fails.
For concurrency, a single lock is simple but limits parallelism. Sharding or segmented policies can increase throughput but change exact LRU behavior. I would choose based on hit rate, contention, and the cost of stale eviction decisions rather than adding complexity preemptively.