23.7 Relación productor/consumidor:
ArrayBlockingQueue
Una manera de sincronizar los subprocesos productor y consumidor es utilizar las clases del paquete de concu-
rrencia de Java, el cual encapsula la sincronización por nosotros. Java incluye la clase
ArrayBlockingQueue
(del
paquete
java.util.concurrent
); una clase de búfer completamente implementada, segura para los subpro-
cesos, que implementa a la interfaz
BlockingQueue
. Esta interfaz extiende a la interfaz
Queue
que vimos en el
capítulo 19 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 co-
la 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 ante-
rior (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
Array-
BlockingQueue
tiene su tamaño fi jo y no se expandirá para dar cabida a más elementos.
El programa de las fi guras 23.16 y 23.17 demuestra a un
Productor
y un
Consumidor
accediendo a un
objeto
ArrayBlockingQueue
. La clase
BuferBloqueo
(fi gura 23.16) utiliza un objeto
ArrayBlockingQueue
que almacena un objeto
Integer
(línea 7). En la línea 11 se crea el objeto
ArrayBlockingQueue
y se pasa
1
al
constructor, para que el objeto contenga un solo valor, como hicimos con el objeto
BuferSinSincronizacion
de la fi gura 23.14. Observe que en las líneas 7 y 11 utilizamos genéricos, los cuales se describen en los capítu-
los 18 y 19. En la sección 23.9 hablaremos sobre los búferes con varios elementos. Debido a que nuestra clase
BuferBloqueo
utiliza la clase
ArrayBlockingQueue
(segura para los subprocesos) para administrar el objeto
al búfer compartido,
BuferBloqueo
es en sí segura para los subprocesos, aun cuando no hemos implementado la
sincronización nosotros mismos.
Figura 23.15
| Aplicación con dos subprocesos que manipulan un búfer sin sincronización. (Parte 3 de 3).
Accion Valor Suma producidos Suma consumidos
------ ----- --------------- ---------------
Consumidor lee -1 -1
lee -1 datos incorrectos
Productor escribe 1 1
Consumidor lee 1 0
Consumidor lee 1 1
1 se lee de nuevo
Consumidor lee 1 2
1 se lee de nuevo
Consumidor lee 1 3
1 se lee de nuevo
Consumidor lee 1 4
1 se lee de nuevo
Productor escribe 2 3
Consumidor lee 2 6
Productor escribe 3 6
Consumidor lee 3 9
Productor escribe 4 10
Consumidor lee 4 13
Productor escribe 5 15
Productor escribe 6 21
5 se pierde
Consumidor lee 6 19
Consumidor leyo valores, el total es 19
Terminando Consumidor
Productor escribe 7 28
7 nunca se lee
Productor escribe 8 36
8 nunca se lee
Productor escribe 9 45
9 nunca se lee
Productor escribe 10 55
10 nunca se lee
Productor termino de producir
Terminando Productor
23.7 Relación
productor/consumidor:
ArrayBlockingQueue
949
23_MAQ_CAP_23_DEITEL.indd949
4/19/081:33:45AM