The first restriction can be implemented with a map of AtomicBoolean. This probably doesn't need to be a ConcurrentHashMap, since you won't be changing the map's keys after initialization. Don't forget to reset the feed's value to false when you're done.
checkAndProcessFeed(Feed feed, Map<String, AtomicBoolean> map) {
while(!map.get(feed.type).compareAndSet(false, true)) // assuming the AtomicBooleans were initialized to false
Thread.sleep(500);
}
process(feed); // at this point map.get(feed.type).get() == true
map.get(feed.type).set(false); // reset the AtomicBoolean to false
}
The other two restrictions can be implemented with AtomicInteger, used to maintain a count of clients and per-client files; decrement when processing is complete, and increment with compare-and-set to start a new client/file.
final int maxClient = 5;
AtomicInteger clientCount = new AtomicInteger(0);
ConcurrentLinkedQueue<Client> queue = new ConcurrentLinkedQueue<>(); // hold waiting clients
while(true) {
int temp = clientCount.intValue();
if(!queue.isEmpty() && clientCount.compareAndSet(temp, temp + 1) { // thread-safe increment
process(clients.poll()); // don't forget to decrement the clientCount when the processing finishes
} else Thread.sleep(500);
}