Both waiting threads receive a notification. Both waiting threads wake up inside the loop. Both have to check the condition in order to get out of the loop. But one of the waiting threads will go first, and will slam the door shut on the other one.
When a waiting thread gets notified it is still in the wait method, it can't leave the wait method until it acquires the lock. (Remember the wait is inside a synchronized method and the thread gave up the lock on the ShareResource object when it started waiting.) Of course only one thread can acquire the lock at a time.
Of the two notified threads, the first to acquire the lock will leave the wait method, then check the loop condition. It finds that n is 0 and it can exit the loop. Then the thread increments n. All of this happens with the lock held so no other threads can interfere.
All this time the second thread has been blocked; it was woken up by the same notification as the first thread, but it couldn't get the lock. Once the first thread has exited the p method, releasing the lock, the second thread can take the lock and exit the wait method. At that point it checks the while loop condition, finds n is greater than 0 thanks to the first thread, then enters the wait method again and it's back where it started.
Notice that notifyAll is typically wasteful because multiple threads get woken up but only one can make progress.