La cola delante de nuestros contactos son sin bloqueo de cola, como PriorityQueue, LinkedList (LinkedList es una lista doblemente enlazada, que implementa la interfaz quitar de la cola).
Cuando se utiliza sin bloqueo de cola hay una gran pregunta es la siguiente: no va a obstruir el flujo actual, entonces el consumidor en la cara de similares - cuando el modelo de productor, es necesario aplicar las políticas y la sincronización entre hilos adicionales despierta la política, esta es muy complicado de implementar. Pero con el bloqueo de cola no es el caso, se produciría el bloqueo del subproceso actual, tales como elementos de toma de hilo de una cola de bloqueo vacío, en cuyo caso se bloqueará el hilo hasta que la cola de bloqueo con los elementos. Cuando hay elementos en la cola, hilo bloqueado se activará automáticamente (no es necesario para escribir el código de despertar). Esto proporciona una gran comodidad.
1. cola sin bloqueo en varios métodos principales:
añadir (E e): el elemento se inserta en el extremo de la cola de correo, si se ha insertado con éxito, devuelve true; si falla la inserción (es decir, la cola está llena), se producirá una excepción;
eliminar (): quitar la cabeza de los elementos de la cola eliminadas si tiene éxito, devuelve true; si no la eliminación (la cola está vacía), se produce una excepción;
oferta (E e): el elemento se inserta en el extremo de la cola de correo, si se ha insertado con éxito, devuelve true; si falla la inserción (es decir, la cola está llena), se devuelve false;
poll (): eliminar el equipo y obtener el primer elemento, si tiene éxito, se devuelve la cabeza del elemento de la cola, de lo contrario devolver null;
peek (): Obtiene el primer elemento del equipo, si tiene éxito, se devuelve la cabeza del elemento de la cola, de lo contrario nula
Sin bloqueo de cola, generalmente se recomienda utilizar tres métodos ofrecen, sondeo y PEEK, añadir y eliminar métodos obsoletos. Dado que el uso de tres métodos ofrecen, sondeo y el valor peek está determinada por la operación de retorno éxito, el uso de agregar y quitar un método no puede lograr tales resultados. Tenga en cuenta que el método de cola de no bloqueo no están sincronizados medidas.
2. La cola de bloqueo en varios métodos principales:
El bloqueo de cola incluye la mayor parte de los métodos de la no-bloqueo de cola, cinco métodos mencionados anteriormente están presentes en la cola de bloqueo, pero tenga en cuenta que estos cinco métodos en los que bloquean la cola se han sincronizado medidas. Además, la cola de bloqueo proporciona otro método muy útil de cuatro:
poner (E e): método put elemento se utiliza para depositar la cola, si la cola está llena, a la espera;
tomar (): tomar el primer método se utiliza para tomar los elementos del equipo, si la cola está vacía, a la espera;
oferta (E e, largo tiempo de espera, la unidad de TimeUnit): Oferta método de elementos se utiliza para depositar la cola, si la cola está llena, a continuación, espera durante un cierto tiempo, cuando se alcanza el límite de tiempo si no se ha insertado con éxito, devuelve falso, de lo contrario return true;
poll (largo tiempo de espera, la unidad de TimeUnit): método de sondeo se utiliza para tomar elementos del primer equipo, si la cola está vacía, entonces esperar un cierto período de tiempo, cuando se alcanza el límite de tiempo si tomar, o nula, de lo contrario elemento hecho;
- Lanza una excepción: cuando la cola está llena, si vas a la cola para insertar elementos, lanza IllegalStateException ( "QueueFull") es una excepción. Cuando la cola está vacía cuando se recupera un elemento de la cola NoSuchElementException será una excepción.
- Devuelve el valor especial: Cuando se inserta un elemento en la cola, devuelve el elemento se inserta el éxito, devuelve verdadero si tiene éxito, de lo contrario devuelve false. Si el método es eliminar, un elemento se elimina de la cola, se devuelve el elemento si se devuelve no nulo.
- Se ha bloqueado: Cuando el bloqueo de cola está llena, si el hilo productor para poner la cola de elemento, la cola se bloqueará hasta que el hilo productor hasta que la cola está disponible o no responde a abortar. Cuando la cola está vacía, si el hilo consumidor toma elementos de la cola, la cola se bloqueará hilo consumidor en vivo hasta que la cola no está vacía.
- Tiempo de espera de salida: Cuando el bloqueo de la cola está llena, si el hilo productor insertar elementos en la cola, la cola bloqueará el hilo productor desde hace algún tiempo, si hay más de un tiempo determinado, el hilo termina productor.
II. Siete cola de bloqueo importante
Desde Java 1.5, ofertas cola de bloqueo en varias paquete java.util.concurrent, principalmente en lo siguiente:
1.ArrayBlockingQueue: Sobre la base de la matriz para lograr una cola de bloqueo delimitada que interna mantiene una datos de longitud fija de tampón de cola (la cola consiste en una matriz), los elementos de esta cola se ordenan de acuerdo con el principio de primero en primero en salir (FIFO), y debe especificar el tamaño al crear objetos ArrayBlockingQueue capacidad . también ArrayBlockingQueue mantenido dentro de dos variables enteras, identificar respectivamente la localización de la cabeza de la cola y la cola de la matriz.
Y también puede especificar no la equidad y la justicia, la feria no predeterminada. El llamado un acceso justo a los medios de colas que el hilo bloqueado, puede seguir la cola de acceso e impida el normal, que es para bloquear el hilo para acceder a la cola. La injusticia es un hilo que esperar a que no justo cuando la cola está disponible, el hilo bloqueado puede ser elegible para competir por el acceso a la cola, es posible acceder por fin el hilo bloqueado cola. Con el fin de asegurar la equidad, generalmente disminuye el rendimiento. Podemos crear un equipo de utilización igualdad de condiciones bloqueo de código de la siguiente columna.
ArrayBlockingQueue fairQueue = new ArrayBlockingQueue(1000,true); public ArrayBlockingQueue(int capacity, boolean fair) {
if (capacity <= 0) throw new IllegalArgumentException();
this.items = new Object[capacity];
lock = new ReentrantLock(fair); //可以看出访问者的公平性是使用可重入锁实现的
notEmpty = lock.newCondition();
notFull = lock.newCondition();
}
2.LinkedBlockingQueue:基于链表实现的一个有界阻塞队列,内部维持着一个数据缓冲队列(该队列由链表构成),此队列按照先进先出的原则对元素进行排序。当生产者往队列中放入一个数据时,队列会从生产者手中获取数据,并缓存在队列内部,而生产者立即返回;只有当队列缓冲区达到最大值缓存容量时(可以通过LinkedBlockingQueue的构造函数指定该值),才会阻塞生产者队列,直到消费者从队列中消费掉一份数据,生产者线程将会被唤醒,反之对于消费者这端的处理也基于同样的原理。在创建LinkedBlockingQueue对象时如果不指定容量大小,则默认大小为Integer.MAX_VALUE。这样的话,如果生产者的速度一旦大于消费者的速度,也许还没有等到队列满阻塞产生,系统内存就有可能已经被消耗殆尽了。
LinkedBlockingQueue之所以能够高效的处理并发数据,是因为其对于生产者端和消费者端分别采用了独立的锁来控制数据同步,这也意味着在高并发的情况下生产者和消费者可以并行地操作队列中的数据,以此来提高整个队列的并发性能。
3.PriorityBlockingQueue:支持优先级排序的无界阻塞队列,以上2种队列都是先进先出队列,而PriorityBlockingQueue却不是,它会按照元素的优先级对元素进行排序,默认情况下元素采取自然顺序排列,也可以通过构造函数传入的Compator对象来决定。并且也是按照优先级顺序出队,每次出队的元素都是优先级最高的元素。在实现PriorityBlockingQueue时,内部控制线程同步的锁采用的是公平锁。需要注意的是PriorityBlockingQueue并不会阻塞数据生产者,而只是在没有可消费的数据时阻塞数据的消费者,因此使用的时候要特别注意,生产者生产数据的速度绝对不能快于消费者消费数据的速度,否则时间一长,会最终耗尽所有的可用堆内存空间。注意,此阻塞队列为无界阻塞队列,即容量没有上限(通过源码就可以知道,它没有容器满的信号标志)。
4.DelayQueue:基于PriorityQueue,一种支持延时的获取元素的无界阻塞队列,DelayQueue中的元素只有当其指定的延迟时间到了,才能够从队列中获取到该元素。DelayQueue也是一个无界队列,因此往队列中插入数据的操作(生产者)永远不会被阻塞,而只有获取数据的操作(消费者)才会被阻塞。
transfer()方法:如果当前有消费者正在等待接收元素(消费者使用take()方法或带时间限制的poll()方法),transfer()方法可以把生产者传入的元素立刻传输给消费者;如果没有消费者在等待接收元素,transfer()方法会将元素存放到队列的tail节点,并等到该元素被消费者消费了才返回。
transfer()方法的关键代码如下:
Node pred = tryAppend(s, haveData); return awaitMatch(s, pred, e, (how == TIMED), nanos);
第一行代码是试图把存放当前元素的s节点作为tail节点,第二行代码是让CPU自旋等待消费者消费元素。因为自旋会消耗CPU,所以自旋一定的次数后使用Thread.yield()方法来暂停当前正在执行的线程,并执行其他线程。
tryTransfer()方法:该方法是用来试探生产者传入的元素是否能直接传给消费者,如果没有消费者等待接收元素,则返回false。与transfer()方法的区别:tryTransfer()方法是立即返回(无论消费者是否接收),transfer()方法是必须等到消费者消费了才返回。对于带有时间限制的tryTransfer(E e, long timeout, TimeUnit unit)方法,则是试图把生产者传入的元素直接传给消费者,但是如果没有消费者消费该元素则等待指定的时间之后再返回,如果超时还没消费元素,则返回false,如果在超时时间内消费了元素,则返回true。
public class ArrayBlockingQueue<E> extends AbstractQueue<E> implements BlockingQueue<E>, java.io.Serializable { /** * Serialization ID. This class relies on default serialization * even for the items array, which is default-serialized, even if * it is empty. Otherwise it could not be declared final, which is * necessary here. */ private static final long serialVersionUID = -817911632652898426L; /** The queued items */ final Object[] items; /** items index for next take, poll, peek or remove */ int takeIndex; /** items index for next put, offer, or add */ int putIndex; /** Number of elements in the queue */ int count; /** Main lock guarding all access */ final ReentrantLock lock; /** Condition for waiting takes */ private final Condition notEmpty; /** Condition for waiting puts */ private final Condition notFull; transient Itrs itrs = null;
public void put(E e) throws InterruptedException { checkNotNull(e); final ReentrantLock lock = this.lock; lock.lockInterruptibly();//操作之前先上锁 try { while (count == items.length)//当队列满了 notFull.await(); //则生产者不继续添加,而是将自己阻塞,直到有消费者来消费并将自己唤醒后,才可以继续执行 enqueue(e); } finally { lock.unlock(); //释放锁 } } private void enqueue(E x) {//相当于add()方法 final Object[] items = this.items; items[putIndex] = x;//在队尾添加元素 if (++putIndex == items.length)//索引自增,如果已是最后一个位置,重新设置 putIndex = 0 putIndex = 0; count++; notEmpty.signal(); } public E take() throws InterruptedException {//由于此时并发容器已满,所以生产者生产失败,释放了锁,轮到消费者执行 final ReentrantLock lock = this.lock; lock.lockInterruptibly(); //操作前先上锁 try { while (count == 0)//判断容器不为空 notEmpty.await(); return dequeue();//调用该方法 } finally { lock.unlock(); } } private E dequeue() {//相当于remove() final Object[] items = this.items;//获取数组容器 E x = (E) items[takeIndex];//获取队首元素,因为ArrayBlockingQueue是先进先出队列 items[takeIndex] = null;//将该位置置空 if (++takeIndex == items.length)//索引自增,如果已是最后一个位置,重新设置 putIndex = 0 takeIndex = 0; count--;//将容器中元素个数减一 if (itrs != null) itrs.elementDequeued(); notFull.signal();//唤醒其他被阻塞的线程,由于刚才生产者因容器已满而被阻塞掉,这时候就会被该线程唤醒了,唤醒之后就可继续它的生产工作。 return x; }