Java中的队列都有哪些,有什么区别

Queue: 基本上,一个队列就是一个先入先出(FIFO)的数据结构

Queue接口与List、Set同一级别,都是继承了Collection接口。LinkedList实现了Deque接 口。

 

Queue的实现


1、没有实现的阻塞接口的LinkedList: 实现了java.util.Queue接口和java.util.AbstractQueue接口
  内置的不阻塞队列: PriorityQueue 和 ConcurrentLinkedQueue
  PriorityQueue 和 ConcurrentLinkedQueue 类在 Collection Framework 中加入两个具体集合实现。 
  PriorityQueue 类实质上维护了一个有序列表。加入到 Queue 中的元素根据它们的天然排序(通过其 java.util.Comparable 实现)或者根据传递给构造函数的 java.util.Comparator 实现来定位。
  ConcurrentLinkedQueue 是基于链接节点的、线程安全的队列。并发访问不需要同步。因为它在队列的尾部添加元素并从头部删除它们,所以只要不需要知道队列的大 小,          ConcurrentLinkedQueue 对公共集合的共享访问就可以工作得很好。收集关于队列大小的信息会很慢,需要遍历队列。


2)实现阻塞接口的:
  java.util.concurrent 中加入了 BlockingQueue 接口和五个阻塞队列类。它实质上就是一种带有一点扭曲的 FIFO 数据结构。不是立即从队列中添加或者删除元素,线程执行操作阻塞,直到有空间或者元素可用。
五个队列所提供的各有不同:
  * ArrayBlockingQueue :一个由数组支持的有界队列。
  * LinkedBlockingQueue :一个由链接节点支持的可选有界队列。
  * PriorityBlockingQueue :一个由优先级堆支持的无界优先级队列。
  * DelayQueue :一个由优先级堆支持的、基于时间的调度队列。
  * SynchronousQueue :一个利用 BlockingQueue 接口的简单聚集(rendezvous)机制

 

 

 

下表显示了jdk1.5中的阻塞队列的操作:

 

  add        增加一个元索                     如果队列已满,则抛出一个IIIegaISlabEepeplian异常
  remove   移除并返回队列头部的元素    如果队列为空,则抛出一个NoSuchElementException异常
  element  返回队列头部的元素             如果队列为空,则抛出一个NoSuchElementException异常
  offer       添加一个元素并返回true       如果队列已满,则返回false
  poll         移除并返问队列头部的元素    如果队列为空,则返回null
  peek       返回队列头部的元素             如果队列为空,则返回null
  put         添加一个元素                      如果队列满,则阻塞
  take        移除并返回队列头部的元素     如果队列为空,则阻塞

 

remove、element、offer 、poll、peek 其实是属于Queue接口。 

 

阻塞队列的操作可以根据它们的响应方式分为以下三类:aad、removee和element操作在你试图为一个已满的队列增加元素或从空队列取得元素时 抛出异常。当然,在多线程程序中,队列在任何时间都可能变成满的或空的,所以你可能想使用offer、poll、peek方法。这些方法在无法完成任务时 只是给出一个出错示而不会抛出异常。

 

注意:poll和peek方法出错进返回null。因此,向队列中插入null值是不合法的

 

最后,我们有阻塞操作put和take。put方法在队列满时阻塞,take方法在队列空时阻塞。

 

 

LinkedBlockingQueue的容量是没有上限的(说的不准确,在不指定时容量为Integer.MAX_VALUE,不要然的话在put时怎么会受阻呢),但是也可以选择指定其最大容量,它是基于链表的队列,此队列按 FIFO(先进先出)排序元素。


ArrayBlockingQueue在构造时需要指定容量, 并可以选择是否需要公平性,如果公平参数被设置true,等待时间最长的线程会优先得到处理(其实就是通过将ReentrantLock设置为true来 达到这种公平性的:即等待时间最长的线程会先操作)。通常,公平性会使你在性能上付出代价,只有在的确非常需要的时候再使用它。它是基于数组的阻塞循环队 列,此队列按 FIFO(先进先出)原则对元素进行排序。


PriorityBlockingQueue是一个带优先级的 队列,而不是先进先出队列。元素按优先级顺序被移除,该队列也没有上限(看了一下源码,PriorityBlockingQueue是对 PriorityQueue的再次包装,是基于堆数据结构的,而PriorityQueue是没有容量限制的,与ArrayList一样,所以在优先阻塞 队列上put时是不会受阻的。虽然此队列逻辑上是无界的,但是由于资源被耗尽,所以试图执行添加操作可能会导致 OutOfMemoryError),但是如果队列为空,那么取元素的操作take就会阻塞,所以它的检索操作take是受阻的。另外,往入该队列中的元 素要具有比较能力。


DelayQueue(基于PriorityQueue来实现的)是一个存放Delayed 元素的无界阻塞队列,只有在延迟期满时才能从中提取元素。该队列的头部是延迟期满后保存时间最长的 Delayed 元素。如果延迟都还没有期满,则队列没有头部,并且poll将返回null。当一个元素的 getDelay(TimeUnit.NANOSECONDS) 方法返回一个小于或等于零的值时,则出现期满,poll就以移除这个元素了。此队列不允许使用 null 元素。

 

 

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class BlockingQueueTest {
 /**
 定义装苹果的篮子
  */
 public static class Basket{
  // 篮子,能够容纳3个苹果
  BlockingQueue<String> basket = new ArrayBlockingQueue<String>(3);

  // 生产苹果,放入篮子
  public void produce() throws InterruptedException{
   // put方法放入一个苹果,若basket满了,等到basket有位置
   basket.put("An apple");
  }
  // 消费苹果,从篮子中取走
  public String consume() throws InterruptedException{
   // get方法取出一个苹果,若basket为空,等到basket有苹果为止
   String apple = basket.take();
   return apple;
  }

  public int getAppleNumber(){
   return basket.size();
  }

 }
 // 测试方法
 public static void testBasket() {
  // 建立一个装苹果的篮子
  final Basket basket = new Basket();
  // 定义苹果生产者
  class Producer implements Runnable {
   public void run() {
    try {
     while (true) {
      // 生产苹果
      System.out.println("生产者准备生产苹果:" 
        + System.currentTimeMillis());
      basket.produce();
      System.out.println("生产者生产苹果完毕:" 
        + System.currentTimeMillis());
      System.out.println("生产完后有苹果:"+basket.getAppleNumber()+"个");
      // 休眠300ms
      Thread.sleep(300);
     }
    } catch (InterruptedException ex) {
    }
   }
  }
  // 定义苹果消费者
  class Consumer implements Runnable {
   public void run() {
    try {
     while (true) {
      // 消费苹果
      System.out.println("消费者准备消费苹果:" 
        + System.currentTimeMillis());
      basket.consume();
      System.out.println("消费者消费苹果完毕:" 
        + System.currentTimeMillis());
      System.out.println("消费完后有苹果:"+basket.getAppleNumber()+"个");
      // 休眠1000ms
      Thread.sleep(1000);
     }
    } catch (InterruptedException ex) {
    }
   }
  }

  ExecutorService service = Executors.newCachedThreadPool();
  Producer producer = new Producer();
  Consumer consumer = new Consumer();
  service.submit(producer);
  service.submit(consumer);
  // 程序运行10s后,所有任务停止
  try {
   Thread.sleep(10000);
  } catch (InterruptedException e) {
  }
  service.shutdownNow();
 }
 public static void main(String[] args) {
  BlockingQueueTest.testBasket();
 }
}

在java5中新增加了java.util.Queue接口,用以支持队列的常见操作。Queue接口与List、Set同一级别,都是继承了Collection接口。
Queue使用时要尽量避免Collection的add()和remove()方法,而是要使用offer()来加入元素,使用poll()来获取并移出元素。它们的优
点是通过返回值可以判断成功与否,add()和remove()方法在失败的时候会抛出异常。 如果要使用前端而不移出该元素,使用
element()或者peek()方法。
值得注意的是LinkedList类实现了Queue接口,因此我们可以把LinkedList当成Queue来用。

LinkedList实现了Queue接口。Queue接口窄化了对LinkedList的方法的访问权限(即在方法中的参数类型如果是Queue时,就完全只能访问Queue接口所定义的方法 了,而不能直接访问 LinkedList的非Queue的方法),以使得只有恰当的方法才可以使用。BlockingQueue 继承了Queue接口

 

import java.util.Queue;
import java.util.LinkedList;
public class TestQueue {
     public static void main(String[] args) {
         Queue<String> queue = new LinkedList<String>();
         queue.offer("Hello");
         queue.offer("World!");
         queue.offer("你好!");
         System.out.println(queue.size());
         String str;
         while((str=queue.poll())!=null){
             System.out.print(str);
         }
         System.out.println();
         System.out.println(queue.size());
     }
}

 

### 回答1: Java 编程,消息队列通常被用于以下几个方面: 1. 异步处理:消息队列可以将任务异步化,即生产者可以将任务放到消息队列,消费者可以从消息队列获取任务并执行,从而降低任务执行的耦合度,提高系统的并发能力和稳定性。 2. 应用解耦:消息队列可以将应用程序之间的耦合度降到最低,因为它们只需要了解如何发送和接收消息即可。例如,一个系统可以将任务发布到消息队列,而其他系统可以通过订阅该消息队列来接收和处理这些任务,从而实现应用之间的解耦。 3. 流量控制:使用消息队列可以对系统的流量进行控制,因为消息队列充当了缓冲区。当系统出现高峰期时,消息队列可以缓存请求,以便消费者能够以更快的速度处理它们。 4. 消息传递:消息队列还可以用于在分布式系统传递消息。由于分布式系统的组件通常是分散在多个节点上的,因此使用消息队列可以在这些节点之间进行消息传递,从而实现系统的协调和管理。 ### 回答2: Java 编程消息队列的作用有以下几个方面: 1. 解耦应用组件:消息队列可以将不同组件或服务之间的依赖关系解耦,使得系统更加灵活和可扩展。通过消息队列,消息的生产者和消费者之间不需要直接进行通信,只需要将消息发送到队列,然后由消费者从队列获取消息进行处理。这样一来,即使某个组件暂时不可用或发生故障,也不会影响整个系统的正常运行。 2. 异步通信:消息队列支持异步通信模式,可以提高系统的性能和吞吐量。当需要对某个任务进行处理时,生产者只需要将消息发送到队列,而无需等待消费者的响应结果。这样可以实现任务的并行处理,提高系统的响应速度和处理能力。 3. 缓冲和削峰:消息队列可以作为一个缓冲区,用于平衡生产者和消费者之间的数据流量差异。当生产者的产生速度大于消费者的处理速度时,可以将消息暂存到队列,避免数据丢失或系统崩溃。同时,消息队列的削峰功能可以在系统负载达到峰值时,通过限制消费者的读取速度,保证系统的稳定性和可用性。 4. 系统解耦和扩展性:通过消息队列,不同的组件或服务可以通过消息的传递进行解耦,从而实现系统的松耦合。当系统需要进行扩展时,新增的组件或服务只需要与消息队列进行交互,而不需要直接修改已有组件的代码。这样可以减少系统改动的范围,降低开发和维护的成本。 总的来说,消息队列Java编程扮演了重要的角色。它可以帮助应用程序实现异步通信、解耦应用组件、提高系统性能和扩展性,并且可以充当缓冲和削峰的作用,保证系统的稳定性和可用性。 ### 回答3: Java编程消息队列的作用主要有以下几点: 1. 解耦:消息队列可以将不同的组件或模块解耦,使其相互之间不直接依赖。一个组件可以将消息发送到消息队列,而不需要直接调用其他组件的方法或接口,从而降低各个组件之间的耦合度。 2. 异步处理:消息队列可以实现异步处理,发送消息的组件可以继续执行其他任务,而无需等待接收消息组件的处理结果。这样可以提高整个系统的并发处理能力和响应速度。 3. 可靠性:消息队列具备持久化特性,消息发送到队列后将在队列保存一段时间,即使消费者暂时不可用,也不会丢失消息。消息队列还可以通过备份和冗余机制,提供高可靠性的消息传递和存储能力。 4. 流量控制和削峰填谷:在高并发或突发流量情况下,消息队列可以通过设定合理的阈值和消费速率,进行流量控制,以避免大量请求直接压到后端系统。这样可以平滑处理高峰期的请求,提高系统的稳定性和可用性。 5. 消息分发和负载均衡:消息队列可以将消息分发给多个消费者,实现负载均衡和任务分配。这样可以更好地利用系统资源,提高整体的处理能力和效率。 6. 顺序保证:有些应用场景,消息的处理顺序很重要。消息队列可以保证按照发送消息的顺序进行消费,确保业务逻辑的正确性。 7. 数据缓冲:消息队列可以作为数据的缓冲区,用于平衡生产者和消费者之间的速率差异。这对于流量峰值过大或者瞬间请求量过大的场景下,可以缓解数据库压力,提高系统的处理能力。 总结起来,Java编程消息队列的作用主要有解耦、异步处理、可靠性、流量控制、负载均衡、顺序保证和数据缓冲。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值