my answer to the first problem would go like this:
From a logical perspective, it depends on the actual purpose of the application, however, we should at least ensure safety and liveness, therefore some locking algorithms are appropriate.
Since the contest could be very serious (legal consequences in case of booking failure) I would opt for a mutual exclusive (ensures safety, namely at most one user will book as the 100th competitor), starvation free (ensures everybody will eventually access the lock), fifo (ensures that users can not overcome each other at booking time and they are served in the order they show up) lock.
From a programming perspective, I would first ask about precise requirements because mentioned use-cases seem to be easily manageable through simple and famous (but not scalable) locking algorithms. The Bakery Lock (Wikipage) satisfies all the properties I mentioned earlier but comes with several disadvantages, namely, it must read as many variables as participant processes. Its implementation in Java should be easy and there are several examples on the Internet.
The philosophy of my answer is the one employed in “The garbage collection handbook”, namely: safety properties must be honored but your design decisions should depend on use-cases; provided hard requirements are to be met more sophisticated algorithms are to be employed.
If you are interested in learning more about concurrency there exist several books about it, I name just two:
The Art of Multiprocessor Programming (chapters from 1 to 10 should suffice), by Shavit & Herlihy
Distributed Algorithms (chapter 10 is about locking), by Nancy Lynch