Cualquier hilo puede "llamar al notify()", a lo que me refiero es que "hay que llamar al notify() del objeto bloqueado".
Es decir, tu llamas a obj.notify() desde el Thread que quieras, pero obj ha de ser el objeto sobre el que los otros Thread han hecho el obj.wait() (aunque sea implicitamente con un wait() si lo hace el mismo obj en uno de sus metodos como era en el caso que tu pusiste).
Respecto a lo que comentas de la explicación de Chuidiang, lamento contradecirla respetuosamente pero esas dos cosas no son ciertas:
.- El Thread que se despierta cuando haces un notify() es "aleatorio y depende de la implementación de la JVM". Supongo que Chuidiang hizo las pruebas en una JVM que lo habia implementado como una cola FIFO y supuso que era así siempre, pero no es cierto como se puede comprobar echando un vistazo al API:
http://java.sun.com/j2se/1.5.0/docs/...tify%28%29 Cita: If any threads are waiting on this object, one of them is chosen to be awakened. The choice is arbitrary and occurs at the discretion of the implementation.
.- wait/notify no llevan "contadores de llamada" así que puedes llamar al notify() 250.000 veces antes del wait(), que el wait() seguirá bloqueandose y sólo se despertará cuando alguien llame a un notify()
después. Es facilísimo de comprobar en el mismo ejemplo que tienes, simplemente pones notify(); antes del wait(); y si fuera cierto que recuerda las llamadas a notify() no se tendría que bloquear. No he encontrado un sítio específico donde esté documentado por que lo aprendí hace muchos años, pero así es.
.- Como comentario extra, la tecnica que usa Chuidiang en sus ejemplos de usar synchronized a nivel de método no se suele recomendar, excepto para bloqueos muy simples, ya que no permite un control refinado de las zonas de bloqueo (se bloquea siempre el objeto entero para cualquier método sincronizado). Es más recomendable usar bloques synchronized sobre objetos, simples, aunque no sirvan más que para eso (típica variable miembro Object lock = new Object();
.
Y como extra un enlace interesante sobre errores habituales:
http://www.javamex.com/tutorials/syn...notify_3.shtml
Ah, y no olvides echarle un vistazo a la libreria Concurrent que viene con el JDK a partir de Java 5, ya que implementa la solución a muchos problemas comunes sin tener que llegar al bajo nivel del wait/notify.. etc.