986

Capítulo 23 Subprocesamiento múltiple

•  

Las 

instrucciones 

synchronized

 se declaran mediante la palabra clave 

synchronized

:

synchronized

 ( 

objeto

 )

{

instrucciones

}

// fin de la instrucción synchronized 

  

en 

donde 

objeto es el objeto cuyo bloqueo de monitor se va a adquirir; generalmente, objeto es 

this

 si es el objeto en 

el que aparece la instrucción 

synchronized

.

•  

Un 

método 

synchronized

 es equivalente a una instrucción 

synchronized

 que encierra el cuerpo completo de un 

método, y que utiliza a 

this

 como el objeto cuyo bloqueo de monitor se va a adquirir.

•  

La 

interfaz 

ExecutorService

 proporciona el método 

awaitTermination

 para obligar a un programa a esperar a 

que los subprocesos completen su ejecución. Este método devuelve el control al que lo llamó, ya sea cuando se com-
pleten todas las tareas que se ejecutan en el objeto 

ExecutorService

, o cuando se agote el tiempo de inactividad 

especifi cado. Si todas las tareas se completan antes de que se agote el tiempo de 

awaitTermination

, este método 

devuelve 

true

; en caso contrario devuelve 

false

. Los dos argumentos para 

awaitTermination

 representan un 

valor de límite de tiempo y una unidad de medida especifi cada con una constante de la clase 

TimeUnit

.

•  Podemos simular la atomicidad al asegurar que sólo un subproceso lleve a cabo un conjunto de operaciones al 

mismo tiempo. La atomicidad se puede lograr mediante el uso de la palabra clave 

synchronized

 para crear una 

instrucción o método 

synchronized

.

•  Al compartir datos inmutables entre subprocesos, debemos declarar los campos de datos correspondientes como 

final

, para indicar que los valores de las variables no cambiarán una vez que se inicialicen.

Sección 23.6 Relación productor/consumidor sin sincronización

•  En una relación productor/consumidor con subprocesamiento múltiple, un subproceso productor genera los datos 

y los coloca en un objeto compartido, llamado búfer. Un subproceso consumidor lee los datos del búfer.

•  Las operaciones con los datos del búfer compartidos por un subproceso productor y un subproceso consumidor 

son dependientes del estado; las operaciones deben proceder sólo si el búfer se encuentra en el estado correcto. Si el 
búfer se encuentra en un estado en el que no esté completamente lleno, el productor puede producir; si el búfer se 
encuentra en un estado en el que no esté completamente vacío, el consumidor puede consumir.

•  Los subprocesos con acceso a un búfer deben sincronizarse para asegurar que lo datos se escriban en el búfer, o se 

lean del búfer sólo si éste se encuentra en el estado apropiado. Si el productor que trata de colocar los siguientes datos 
en el búfer determina que éste se encuentra lleno, el subproceso productor debe esperar hasta que haya espacio. Si 
un subproceso consumidor encuentra el búfer vacío o que los datos anteriores ya se han leído, debe también esperar 
hasta que haya nuevos datos disponibles.

Sección 23.7 Relación productor/consumidor: 

ArrayBlockingQueue

•  Java incluye una clase de búfer completamente implementada llamada 

ArrayBlockingQueue

 en el paquete 

java.

util.concurrent

, que implementa a la interfaz 

BlockingQueue

. Esta interfaz extiende a la interfaz 

Queue

 y declara 

los métodos 

put

 y 

take

, los equivalentes con bloqueo de los métodos 

offer

 y 

poll

 de 

Queue

, respectivamente.

•  

El 

método 

put

 coloca un elemento al fi nal del objeto 

BlockingQueue

, y espera si la cola está llena. El método 

take

elimina un elemento de la parte inicial del objeto 

BlockingQueue

, y espera si la cola está vacía. Estos métodos hacen 

que la clase 

ArrayBlockingQueue

 sea una buena opción para implementar un búfer compartido. Debido a que el 

método

put

 bloquea hasta que haya espacio en el búfer para escribir datos, y el método take bloquea hasta que haya 

nuevos datos para leer, el productor debe producir primero un valor, el consumidor sólo consume correctamente 
hasta después de que el productor escribe un valor, y el productor produce correctamente el siguiente valor (después 
del primero) sólo hasta que el consumidor lea el valor anterior (o primero).

ArrayBlockingQueue

 almacena los datos compartidos en un arreglo. El tamaño de este arreglo se especifi ca como 

argumento para el constructor de 

ArrayBlockingQueue

. Una vez creado, un objeto 

ArrayBlockingQueue

 tiene su 

tamaño fi jo y no se expandirá para dar cabida a más elementos.

Sección 23.8 Relación productor/consumidor con sincronización

•  Usted puede implementar su propio búfer compartido, usando la palabra clave 

synchronized

 y los métodos 

wait

,

notify

 y 

notifyAll

 de 

Object

, que pueden usarse con condiciones para hacer que los subprocesos esperen cuando 

no puedan realizar sus tareas.

•  Si un subproceso obtiene el bloqueo de monitor en un objeto, y después determina que no puede continuar con 

su tarea en ese objeto sino hasta que se cumpla cierta condición, el subproceso puede llamar al método 

wait

 de 

23_MAQ_CAP_23_DEITEL.indd986

4/19/081:34:03AM