El lenguaje Java y el sistema de ejecuci�n soportan la sincronizaxi�n de threads mediante el uso de monitores. En general, un monitor est� asociado con un objeto especifico (una condici�n variable) y funciona como un bloqueo para ese dato. Cuando un thread mantiene el monitor para alg�n dato del objeto, los otros threads est�n bloqueados y no pueden ni inspeccionar ni modificar el dato.
Los segmentos de c�digo dentro de programa que acceden al mismo dato dentro de threads concurrentes separados son conocidos como secciones cr�ticas. En el lenguaje Java, se pueden marcar las secciones cr�ticas del programa con la palabra clave synchronized.
Nota: Generalmente, la secci�n cr�ticas en los programas Java son m�todos. Se pueden marcar segmentos peque�os de c�digo como sincronizados.
Sin embargo, esto viola los paradigmas de la programaci�n orientada a objetos y produce un c�digo que es d�ficil de leer y de mantener. Para la mayor�a de los prop�sitos de programaci�n en Java, es mejor utilizar synchronized s�lo a nivel de m�todos.
En el lenguaje Java se asocia un �nico monitor con cada objeto que tiene un m�todo sincronizado. La clase CubbyHole del ejemplo Producer/Consumer de la p�gina anterior tiene dos m�todos sincronizados: el m�todo put(), que se utiliza para cambiar el valor de CubbyHole, y el m�todo get(), que se utiliza para el recuperar el valor actual. As� el sistema asocia un �nico monitor con cada ejemplar de CubbyHole.
Aqu� tienes el c�digo fuente del objeto CubbyHole. Las l�neas en negrita proporcionan la sincronizaci�n de los threads.
class CubbyHole {
    private int contents;
    private boolean available = false;
    public synchronized int get() {
        while (available == false) {
            try {
                wait();
            } catch (InterruptedException e) {
            }
        }
        available = false;
        notify();
        return contents;
    }
    public synchronized void put(int value) {
        while (available == true) {
            try {
                wait();
            } catch (InterruptedException e) {
            }
        }
        contents = value;
        available = true;
        notify();
    }
}
La clase CubbyHole tiene dos variables privadas: contents, que es el contenido actual de CubbyHole, y la variable booleana available, que indica si se puede recuperar el contenido de CubbyHole. Cuando available es verdadera indica que el Productor ha puesto un nuevo valor en CubbyHole y que el Consumidor todav�a no la ha consumido. El Consumidor s�lo puede consumir el valor de CubbyHole cuando available es verdadera.
Como CubbyHole tiene dos m�todos sincronizados, java proporciona un �nico monitor para cada ejemplar de CubbyHole (incluyendo el compartido por el Productor y el Consumidor). Siempre que el control entra en un m�todo sincronizado, el thread que ha llamado el m�todo adquiere el monitor del objeto cuyo m�todo ha sido llamado. Otros threads no pueden llamar a un m�todo sincronizado del mismo objeto hasta que el monitor sea liberado.
| 
Nota: 
 Los Monitores Java son Re-entrantes. Es decir, el mismo thread puede llamar a un m�todo sincronizado de un objeto para el que ya tiene el monitor, es decir, puede re-adquirir el monitor.  | 
As�, siempre que el Productor llama al m�todo put() de CubbyHole, adquiere el monitor del objeto CubbyHole, y as� evita que el consumidor pueda llamar al m�todo get() de CubbyHole. (El m�todo wait() libera temporalmente el monitor como se ver� m�s adelante).
public synchronized void put(int value) {
        // El productor adquiere el monitor
    while (available == true) {
        try {
            wait();
        } catch (InterruptedException e) {
        }
    }
    contents = value;
    available = true;
    notify();
        // El productor libera el monitor
}
Cuando el m�todo put() retorna, el Productor libera el monitor y por lo tanto desbloquea el objeto CubbyHole.
Siempre que el Consumidor llama al m�todo get() de CubbyHole, adquiere el monitor de ese objeto y por lo tanto evita que el productor pueda llamar al m�todo put().
public synchronized int get() {
        // El consumidor adquier el monitor
    while (available == false) {
        try {
            wait();
        } catch (InterruptedException e) {
        }
    }
    available = false;
    notify();
    return contents;
        // el Consumidor libera el monitor
}
La adquisici�n y liberaci�n del monitor la hace autom�ticamente el sistema de ejecuci�n de Java. Esto asegura que no puedan ocurrir condiciones de competici�n en la implementaci�n de los threads, asegurando la integridad de los datos.
Prueba esto: Elimina las l�neas que est�n en negrita en el listado de la clase CubbyHole mostrada arriba. Recompila el programa y ejecutalo de nuevo. �Qu� sucede? Como no se ha realizado ning�n esfuerzo expl�cito para sicronizar los threads, el Consumidor consume con un abandono temerario y obtiene s�lo una ristra de ceros, en lugar de obtener los enteros entre 0 y 9 exactamente una vez cada uno.