Why the main thread behave like notifyAll() has called and prints the number's value? I thought the main thread should wait until either notify() or notifyAll() is called.
Yes, with the current implementation of threads, the cleanup code does indeed call the notifyAll() method on the Thread class. The reason that this is done is because the threads who are calling the join() method for this exiting thread, is doing so by calling the wait() method.
As mentioned, this is an implementation detail, and hence, may be changed in the future.