阻塞队列

日期: 栏目:常识 浏览:7

阻塞队列(BlockingQueue)是一个支持两个附加操作的队列。这两个附加的操作时:在队列为空时,获取元素的线程会等待队列变为非空。当队列满时,存储元素的线程会等待队列可用。阻塞队列常用于生产者和消费者的场景,生产者是往队列里添加元素的线程,消费者是从队列里取元素的线程。阻塞队列就是生产者存放元素的容器,而消费者也只从容器里拿元素。

 特点:

阻塞在多线程中是指在某些情况下会挂起线程,一旦条件成熟,被阻塞的线程就会自动唤醒。而阻塞队列和唤醒队列是由阻塞队列控制。

试图从空的阻塞队列中获取元素的线程将会被阻塞,直到其他的线程往空的队列里插入新的元素;同样,试图往已满的阻塞队列中添加新元素的线程也会阻塞。直到其他线程从队列中移除一个或多个元素或清空队列后使队列重新空闲起来并后续新增。

阻塞队列的种类:

BlockingQueue的核心方法

 1)抛出异常:

 public static void main(String[] args) { BlockingQueue blockingQueue = new ArrayBlockingQueue<>(3); //add方法添加元素,返回boolean。当阻塞队列满时,再往阻塞队列add插入元素会抛 java.lang.IllegalStateException: Queue full System.out.println(blockingQueue.add("a")); System.out.println(blockingQueue.add("b")); System.out.println(blockingQueue.add("c")); // System.out.println(blockingQueue.add("d")); //element方法返回队列的第一个元素,当阻塞队列为空时,抛出java.util.NoSuchElementException System.out.println(blockingQueue.element()); //remove方法清空队列第一个元素,并返回该元素。当阻塞为空时,抛出java.util.NoSuchElementException System.out.println(blockingQueue.remove()); System.out.println(blockingQueue.remove()); System.out.println(blockingQueue.remove()); // System.out.println(blockingQueue.element()); System.out.println(blockingQueue.remove()); }

2)特殊值

 //特殊值 BlockingQueue blockingQueue = new ArrayBlockingQueue<>(3); //offer方法添加元素,添加成功返回true,添加失败就返回false System.out.println(blockingQueue.offer("a")); System.out.println(blockingQueue.offer("b")); System.out.println(blockingQueue.offer("c")); System.out.println(blockingQueue.offer("d")); //peek方法获取队列里的第一个元素,如果队列为空,则返回null System.out.println(blockingQueue.peek()); //poll方法移除队列里的第一个元素,并返回该元素,如果队列为空,则返回null System.out.println(blockingQueue.poll()); System.out.println(blockingQueue.poll()); System.out.println(blockingQueue.poll()); System.out.println(blockingQueue.poll());

3)一直阻塞

 //一直阻塞 BlockingQueue blockingQueue = new ArrayBlockingQueue<>(3); //put方法添加元素,当阻塞队列满时,再往队列里添加元素,队列会一直阻塞线程直到有其他线程take数据或响应中断退出 blockingQueue.put("a"); blockingQueue.put("b"); blockingQueue.put("c"); // blockingQueue.put("d"); //take方法移除元素,当阻塞队列空时,再从队列里移除元素,队列会一直阻塞线程直到队列可用 System.out.println(blockingQueue.take()); System.out.println(blockingQueue.take()); System.out.println(blockingQueue.take()); // System.out.println(blockingQueue.take());

4)超时退出

 //超时退出 BlockingQueue blockingQueue = new ArrayBlockingQueue<>(3); //offer方法添加元素,并返回boolean,如果队列为满,阻塞一定时间,然后退出 System.out.println(blockingQueue.offer("a", 2L, TimeUnit.SECONDS)); System.out.println(blockingQueue.offer("b", 2L, TimeUnit.SECONDS)); System.out.println(blockingQueue.offer("c", 2L, TimeUnit.SECONDS)); System.out.println(blockingQueue.offer("d", 2L, TimeUnit.SECONDS)); //poll获取队列里第一个元素,如果队列为空时,阻塞一定时间,然后退出 System.out.println(blockingQueue.poll(2L, TimeUnit.SECONDS)); System.out.println(blockingQueue.poll(2L, TimeUnit.SECONDS)); System.out.println(blockingQueue.poll(2L, TimeUnit.SECONDS)); System.out.println(blockingQueue.poll(2L, TimeUnit.SECONDS));

SynchronousQueue

SynchronousQueue没有容量。与其他BlockingQueue不同,SynchronousQueue是一个不存储元素的BlockingQueue。每一个put元素操作都必须要等待一个take操作,否则不能继续添加元素,反之亦然。

public class SynchronousQueueDemo { public static void main(String[] args) throws InterruptedException { BlockingQueue blockingQueue = new SynchronousQueue<>(); new Thread(() -> { try { System.out.println(Thread.currentThread().getName() + "\t put 1"); blockingQueue.put("1"); System.out.println(Thread.currentThread().getName() + "\t put 2"); blockingQueue.put("2"); System.out.println(Thread.currentThread().getName() + "\t put 3"); blockingQueue.put("3"); } catch (InterruptedException e) { e.printStackTrace(); } }, "t1").start(); new Thread(() -> { try { TimeUnit.SECONDS.sleep(2); System.out.println(Thread.currentThread().getName()+"\t"+blockingQueue.take()); TimeUnit.SECONDS.sleep(2); System.out.println(Thread.currentThread().getName()+"\t"+blockingQueue.take()); TimeUnit.SECONDS.sleep(2); System.out.println(Thread.currentThread().getName()+"\t"+blockingQueue.take()); } catch (InterruptedException e) { e.printStackTrace(); } }, "t2").start(); }}

结果:

 

本文地址:https://caijingdemo.com/changshi/80782.html

标签: