I think you want something slightly different above - basically you want the while to be inside the synchronized block, and you want to wait for whatever the maximum time you're actually willing to wait for the data to be loaded is. Otherwise you're just going to do a superflous wait, and there's no reason to continually wait inside the loop. This is covered well in Effective Java -- see end of this comment. 

Should be something like:

```java
synchronized (this) {
    if (!dataLoaded) {
        try {
            wait(2000);
        } catch (InterruptedException e) {
        }
    }
}
```

Then when you set dataLoaded to true -- **every time you set it to be true** -- and note **notifyAll instead of notify** -- see again Effective Java item copied at the end:

```java
synchronized (this) {
    this.notifyAll();
}
```

Otherwise you wait when you don't need to, and without the notify you might as well just use Thread.sleep (but wait and notify is much better!).

Here's more from Effective Java:

Item 50: Never invoke wait outside a loop
The Object.wait method is used to make a thread wait for some condition. It must be invoked inside a synchronized region that locks the object on which it is invoked. This is the standard idiom for using the wait method:

```java
synchronized (obj) {
    while (<condition does not hold>)
        obj.wait();

    ... // Perform action appropriate to condition
}
```

Always use the wait loop idiom to invoke the wait method. Never invoke it outside of a loop. The loop serves to test the condition before and after waiting.
Testing the condition before waiting and skipping the wait if the condition already holds are necessary to ensureliveness. If the condition already holds and notify (or notifyAll) method has already been invoked before a thread waits, there is no guarantee that the thread will ever waken from the wait.
Testing the condition after waiting and waiting again if the condition does not hold are necessary to ensure safety. If the thread proceeds with the action when the condition does not hold, it can destroy the invariants protected by the lock. There are several reasons a thread might wake up when the condition does not hold:
	•	Another thread could have obtained the lock and changed the protected state between the time a thread invokednotify and the time the waiting thread woke up.
	•	Another thread could have invoked notify accidentally or maliciously when the condition did not hold. Classes expose themselves to this sort of mischief by waiting on publicly accessible objects. Any wait contained in a synchronized method of a publicly accessible object is susceptible to this problem.
	•	The notifying thread could be overly “generous” in waking waiting threads. For example, the notifying thread must invoke notifyAll even if only some of the waiting threads have their condition satisfied.
	•	The waiting thread could wake up in the absence of a notify. This is known as a spurious wakeup. Although The Java Language Specification[JLS] does not mention this possibility, many JVM implementations use threading facilities in which spurious wakeups are known to occur, albeit rarely [Posix, 11.4.3.6.1].
A related issue is whether you should use notify or notifyAll to wake waiting threads. (Recall that notify wakes a single waiting thread, assuming such a thread exists, and notifyAll wakes all waiting threads.) It is often said that you should always use notifyAll. This is reasonable, conservative advice, assuming that all wait invocations are insidewhile loops. It will always yield correct results because it guarantees that you'll wake the threads that need to be awakened. You may wake some other threads too, but this won't affect the correctness of your program. These threads will check the condition for which they're waiting and, finding it false, will continue waiting.
As an optimization, you may choose to invoke notify instead of notifyAll if all threads that could be in the wait-set are waiting for the same condition and only one thread at a time can benefit from the condition becoming true. Both of these conditions are trivially satisfied if only a single thread waits on a particular object (as in the WorkQueue example,Item 49).
Even if these conditions appear true, there may be cause to use notifyAll in place of notify. Just as placing the waitinvocation in a loop protects against accidental or malicious notifications on a publicly accessible object, using notifyAllin place of notify protects against accidental or malicious waits by an unrelated thread. Such waits could otherwise “swallow” a critical notification, leaving its intended recipient waiting indefinitely. The reason that notifyAll was notused in the WorkQueue example is that the worker thread waits on a private object (queue) so there is no danger of accidental or malicious waits.
There is one caveat concerning the advice to use notifyAll in preference to notify. While the use of notifyAllcannot harm correctness, it can harm performance. In fact, it systematically degrades the performance of certain data structures from linear in the number of waiting threads to quadratic. The class of data structures so affected are those for which only a certain number of threads are granted some special status at any given time and other threads must wait. Examples include semaphores, bounded buffers, and read-write locks.
If you are implementing this sort of data structure and you wake up each thread as it becomes eligible for “special status,” you wake each thread once for a total of n wakeups. If you wake all n threads when only one can obtain special status and the remaining n-1 threads go back to waiting, you will end up with n + (n – 1) + (n – 2) … + 1 wakeups by the time all waiting threads have been granted special status. The sum of this series is O(n2). If you know that the number of threads will always be small, this may not be a problem in practice, but if you have no such assurances, it is important to use a more selective wakeup strategy.
If all of the threads vying for special status are logically equivalent, then all you have to do is carefully use notifyinstead of notifyAll. If, however, only some of the waiting threads are eligible for special status at any given time, then you must use a pattern known as Specific Notification [Cargill96, Lea99]. This pattern is beyond the scope of this book.
In summary, always invoke wait from within a while loop, using the standard idiom. There is simply no reason to do otherwise. Usually, you should use notifyAll in preference to notify. There are, however, situations where doing so will impose a substantial performance penalty. If notify is used, great care must be taken to ensure liveness.