文章源自:http://www.cnblogs.com/linjiqin/archive/2013/05/30/3108188.html
并发队列ConcurrentLinkedQueue和阻塞队列LinkedBlockingQueue用法
在Java多线程应用中,队列的使用率很高,多数生产消费模型的首选数据结构就是队列。Java提供的线程安全的Queue可以分为阻塞队列和非阻塞队列,其中阻塞队列的典型例子是BlockingQueue,非阻塞队列的典型例子是ConcurrentLinkedQueue,在实际应用中要根据实际需要选用阻塞队列或者非阻塞队列。
注:什么叫线程安全?这个首先要明确。线程安全就是说多线程访问同一代码,不会产生不确定的结果。
LinkedBlockingQueue
由于LinkedBlockingQueue实现是线程安全的,实现了先进先出等特性,是作为生产者消费者的首选,LinkedBlockingQueue 可以指定容量,也可以不指定,不指定的话,默认最大是Integer.MAX_VALUE,其中主要用到put和take方法,put方法在队列满的时候会阻塞直到有队列成员被消费,take方法在队列空的时候会阻塞,直到有队列成员被放进来。
package cn.thread; import java.util.concurrent.BlockingQueue; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.LinkedBlockingQueue; /** * 多线程模拟实现生产者/消费者模型 * * @author 林计钦 * @version 1.0 2013-7-25 下午05:23:11 */ public class BlockingQueueTest2 { /** * * 定义装苹果的篮子 * */ public class Basket { // 篮子,能够容纳3个苹果 BlockingQueue<String> basket = new LinkedBlockingQueue<String>(3); // 生产苹果,放入篮子 public void produce() throws InterruptedException { // put方法放入一个苹果,若basket满了,等到basket有位置 basket.put("An apple"); } // 消费苹果,从篮子中取走 public String consume() throws InterruptedException { // take方法取出一个苹果,若basket为空,等到basket有苹果为止(获取并移除此队列的头部) return basket.take(); } } // 定义苹果生产者 class Producer implements Runnable { private String instance; private Basket basket; public Producer(String instance, Basket basket) { this.instance = instance; this.basket = basket; } public void run() { try { while (true) { // 生产苹果 System.out.println("生产者准备生产苹果:" + instance); basket.produce(); System.out.println("!生产者生产苹果完毕:" + instance); // 休眠300ms Thread.sleep(300); } } catch (InterruptedException ex) { System.out.println("Producer Interrupted"); } } } // 定义苹果消费者 class Consumer implements Runnable { private String instance; private Basket basket; public Consumer(String instance, Basket basket) { this.instance = instance; this.basket = basket; } public void run() { try { while (true) { // 消费苹果 System.out.println("消费者准备消费苹果:" + instance); System.out.println(basket.consume()); System.out.println("!消费者消费苹果完毕:" + instance); // 休眠1000ms Thread.sleep(1000); } } catch (InterruptedException ex) { System.out.println("Consumer Interrupted"); } } } public static void main(String[] args) { BlockingQueueTest2 test = new BlockingQueueTest2(); // 建立一个装苹果的篮子 Basket basket = test.new Basket(); ExecutorService service = Executors.newCachedThreadPool(); Producer producer = test.new Producer("生产者001", basket); Producer producer2 = test.new Producer("生产者002", basket); Consumer consumer = test.new Consumer("消费者001", basket); service.submit(producer); service.submit(producer2); service.submit(consumer); // 程序运行5s后,所有任务停止 // try { // Thread.sleep(1000 * 5); // } catch (InterruptedException e) { // e.printStackTrace(); // } // service.shutdownNow(); } }
ConcurrentLinkedQueue
ConcurrentLinkedQueue是Queue的一个安全实现.Queue中元素按FIFO原则进行排序.采用CAS操作,来保证元素的一致性。LinkedBlockingQueue是一个线程安全的阻塞队列,它实现了BlockingQueue接口,BlockingQueue接口继承自java.util.Queue接口,并在这个接口的基础上增加了take和put方法,这两个方法正是队列操作的阻塞版本。
package cn.thread; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class ConcurrentLinkedQueueTest { private static ConcurrentLinkedQueue<Integer> queue = new ConcurrentLinkedQueue<Integer>(); private static int count = 2; // 线程个数 //CountDownLatch,一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。 private static CountDownLatch latch = new CountDownLatch(count); public static void main(String[] args) throws InterruptedException { long timeStart = System.currentTimeMillis(); ExecutorService es = Executors.newFixedThreadPool(4); ConcurrentLinkedQueueTest.offer(); for (int i = 0; i < count; i++) { es.submit(new Poll()); } latch.await(); //使得主线程(main)阻塞直到latch.countDown()为零才继续执行 System.out.println("cost time " + (System.currentTimeMillis() - timeStart) + "ms"); es.shutdown(); } /** * 生产 */ public static void offer() { for (int i = 0; i < 100000; i++) { queue.offer(i); } } /** * 消费 * * @author 林计钦 * @version 1.0 2013-7-25 下午05:32:56 */ static class Poll implements Runnable { public void run() { // while (queue.size()>0) { while (!queue.isEmpty()) { System.out.println(queue.poll()); } latch.countDown(); } } }
运行结果:
costtime 2360ms
改用while (queue.size()>0)后
运行结果:
cost time 46422ms
结果居然相差那么大,看了下ConcurrentLinkedQueue的API原来.size()是要遍历一遍集合的,难怪那么慢,所以尽量要避免用size而改用isEmpty().
总结了下, 在单位缺乏性能测试下,对自己的编程要求更加要严格,特别是在生产环境下更是要小心谨慎。
相关推荐
ConcurrentLinkedQueue使用了高级并发原语,如 CAS(Compare and Swap),以非阻塞方式实现队列操作。当队列为空时,尝试获取元素的线程不会被阻塞,而是立即返回null。尽管无界,但内存限制仍然存在,若无法分配更...
- Java 提供了多种队列实现,如 `LinkedList`、`ArrayDeque` 和并发类 `ConcurrentLinkedQueue`、`LinkedBlockingQueue` 等。其中,`ConcurrentLinkedQueue` 是一个非阻塞的线程安全队列,而 `LinkedBlockingQueue`...
通过队列工厂,可以在运行时动态选择不同类型的队列,比如阻塞队列(`BlockingQueue`)或并发队列(`ConcurrentLinkedQueue`)。 例如,可以创建一个`QueueFactory`类,包含一个`createQueue()`方法,该方法根据...
此外,还有**并发队列**,如Java的`ConcurrentLinkedQueue`,它在并发环境下提供高效的线程安全操作。这种队列使用非阻塞算法,通过 CAS(Compare and Swap)操作来保证并发一致性,降低了锁的使用,提高了性能。 ...
3. **并发容器**:Java的`java.util.concurrent`包提供了多种并发队列,如`ArrayBlockingQueue`、`LinkedBlockingQueue`和`ConcurrentLinkedQueue`等,它们为多线程环境提供了高效的队列操作。 4. **工作窃取算法**...
2. **并发队列**:并发队列如`ConcurrentLinkedQueue`或`LinkedBlockingQueue`,是线程安全的数据结构,用于在多线程环境中存储和传递任务。它们提供了高效的并发操作,例如添加、移除元素,同时保证了数据的一致性...
`LinkedBlockingQueue`和`ArrayBlockingQueue`是两个常见的阻塞队列实现。 3. **并发工具**:Java并发库提供了一些工具类,如`ExecutorService`和`ThreadPoolExecutor`,它们使用队列来管理待执行的任务。这些工具...
- `ConcurrentLinkedQueue`:无界并发队列,基于链接节点实现,内部使用CAS(Compare And Swap)操作保证线程安全。 - `BlockingQueue`:阻塞队列,如`ArrayBlockingQueue`和`LinkedBlockingQueue`,在队列满或空...
阻塞队列在Java并发包java.util.concurrent中提供了多种实现,如ArrayBlockingQueue、LinkedBlockingQueue、PriorityBlockingQueue、DelayQueue和SynchronousQueue等,每种阻塞队列都根据其特性适用于不同的场景。...
此外,对于高效内存管理和大数据处理,还可以了解基于块的队列(BlockQueue)如 `LinkedBlockingQueue` 和 `ArrayBlockingQueue`,它们提供了阻塞操作,适用于生产者-消费者模型。 总结来说,Java中的队列数据结构...
4. ConcurrentLinkedQueue 是一个基于链接节点的无界并发队列,它使用了链表结构实现 FIFO(先进先出),并且不使用锁,而是依赖于 CAS 操作。 5. LinkedBlockingQueue、ArrayBlockingQueue 和 ...
为了实现一个线程安全的队列,我们可以使用`ConcurrentLinkedQueue`,它是线程安全且无阻塞的队列,适用于高并发场景。另外,`LinkedBlockingQueue`是另一个线程安全的选择,它提供了阻塞操作,当队列为空时,取元素...
`Concurrent`包包含了大量设计精良且线程安全的数据结构,如`ConcurrentHashMap`(线程安全的哈希映射),`ConcurrentLinkedQueue`(无界的并发队列)和`CopyOnWriteArrayList`(写时复制的列表)等。这些数据结构在...
4. **ConcurrentLinkedQueue**: 这是一个基于链表实现的无界并发队列,使用CAS保证线程安全,元素的插入和删除操作是高效的,没有容量限制,但可能会消耗大量内存。 5. **ConcurrentLinkedDeque**: 与...
Java的`java.util.concurrent`包提供了多种阻塞队列实现,如ArrayBlockingQueue、LinkedBlockingQueue和PriorityBlockingQueue等。这些示例代码可能包含如何创建、插入、删除和操作阻塞队列的实例。 2. **卖票的...
3. put、take操作:put方法在队列满时阻塞,take方法在队列空时阻塞。 LinkedBlockingQueue的容量是没有上限的,但是也可以选择指定其最大容量,它是基于链表的队列,此队列按FIFO(先进先出)排序元素。 在java....
例如,对于大量并发插入和删除的操作,`ArrayDeque`由于其非阻塞特性可能是更好的选择。而对于需要保证线程安全的场景,`BlockingQueue`接口及其实现如`LinkedBlockingQueue`提供了丰富的并发控制机制。 总之,理解...
- **阻塞队列(Blocking Queues)**:如`ArrayBlockingQueue`和`LinkedBlockingQueue`,在生产者消费者模式中广泛应用,线程安全且高效。 - **并发集合(Concurrent Collections)**:如`ConcurrentHashMap`、`...