一、ConcurrentLinkedQueue

是一个适合在高并发场景下,无锁,无界的,先进先出原则。不允许为null值,add()、offer()加入元素,这两个方法没区别;poll()、peek()取头元素节点,pull会删除,peek不会。

有一点要注意,轮询条件不能用queue.size();而是用 queue.isEmpty(); 看下面的代码:

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 = 100000;
private static int count2 = 2; // 线程个数
private static CountDownLatch cd = new CountDownLatch(count2);
public static void dothis() {
for (int i = 0; i < count; i++) {
queue.offer(i);
}
}
public static void main(String[] args) throws InterruptedException {
long timeStart = System.currentTimeMillis();
ExecutorService es = Executors.newFixedThreadPool(4);
ConcurrentLinkedQueueTest.dothis();
for (int i = 0; i < count2; i++) {
es.submit(new Poll());
}
cd.await();
System.out.println("cost time "
+ (System.currentTimeMillis() - timeStart) + "ms");
es.shutdown();
}
static class Poll implements Runnable {
@Override
public void run() {
while (queue.size()>0) {
// while (!queue.isEmpty()) {
System.out.println(queue.poll());
}
cd.countDown();
}
}
}

运行结果是:

改用queue.isEmpty()后运行结果是:

结果居然相差那么大,看了下ConcurrentLinkedQueue的API 原来.size() 是要遍历一遍集合的,难怪那么慢,所以尽量要避免用size而改用isEmpty()。

二、ArrayBlockingQueue

基于数组的阻塞队列、有缓冲、定长、没有实现读写分离。有界队列。

下面是ArrayBlockingQueue实现的生产者消费者模式:

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue; public class ArrayBlockingQueueTest {
public static void main(String[] args) {
BlockingQueue queue = new ArrayBlockingQueue(100);
for (int i = 0; i < 10; i++)
new Thread(new ThreadProducer(queue)).start();
for (int i = 0; i < 10; i++)
new Thread(new ThreadConsumer(queue)).start();
}
} class ThreadProducer implements Runnable {
ThreadProducer(BlockingQueue queue) {
this.queue = queue;
} BlockingQueue queue;
static int cnt = 0; public void run() {
String cmd;
while (true) {
cmd = "" + (cnt);
cnt = (cnt + 1) & 0xFFFFFFFF;
try {
queue.put(cmd);
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
} class ThreadConsumer implements Runnable {
ThreadConsumer(BlockingQueue queue) {
this.queue = queue;
} BlockingQueue queue; public void run() {
String cmd;
while (true) {
try {
System.out.println(queue.take());
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

三、LinkedBlockingQueue

基于链表的阻塞队列、有缓冲、读写分离锁(从而实现生产者和消费者操作的完全并行运行)、无界队列

LinkedBlockingQueue实现是线程安全的,实现了FIFO(先进先出)等特性. 是作为生产者消费者的首选,LinkedBlockingQueue 可以指定容量,也可以不指定,不指定的话,默认最大是Integer.MAX_VALUE,其中主要用到put和take方法,put方法在队列满的时候会阻塞直到有队列成员被消费,take方法在队列空的时候会阻塞,直到有队列成员被放进来。

工厂生产制造  生产高大上洒, 还有美女.

消费者有X二代,也有导演.

让消费者抢资源吧.

生产者:

import java.util.UUID;
import java.util.concurrent.BlockingQueue; public class Producer implements Runnable {
private BlockingQueue<String> queue;
private String produce;
public Producer(BlockingQueue<String> queue, String produce) {
this.queue = queue;
if (null != produce)
this.produce = produce;
else this.produce = "null ";
} @Override
public void run() {
String uuid = UUID.randomUUID().toString();
try {
Thread.sleep(200);//生产需要时间
queue.put(produce + " : " + uuid);
System.out.println("Produce \"" + produce + "\" : " + uuid + " " + Thread.currentThread()); } catch (InterruptedException e) {
System.out.println(e.getMessage());
}
}
}

消费者:

import java.util.concurrent.BlockingQueue;

public class Consumer implements Runnable {
private BlockingQueue<String> queue;
private String consumer; public Consumer(BlockingQueue<String> queue, String consumer) {
this.queue = queue;
if (null != consumer)
this.consumer = consumer;
else
this.consumer = "null ";
} @Override
public void run() {
try {
String uuid = queue.take();
System.out.println(consumer + " decayed " + uuid
+ " " + Thread.currentThread());
} catch (InterruptedException e) {
System.out.println(e.getMessage());
}
}
}

调用:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue; public class Tester { public Tester(){
// 队列
LinkedBlockingQueue<String> queue = new LinkedBlockingQueue<String>(10); ExecutorService service = Executors.newCachedThreadPool();
for (int i = 0; i < 6; i++) {
service.submit(new Consumer(queue, "X二代" + i));
service.submit(new Consumer(queue, "导演" + i));
}
for (int i = 0; i < 6; i++) {
service.submit(new Producer(queue, "黄金酒," + i));
service.submit(new Producer(queue, "美女演员" + i));
}
service.shutdown();
}
}

四、SynchronousQueue

没有缓冲的队列,生产者查收的数据或直接被消费者获取并消费。在add前必须take,否则报错。

五、PriorityBlockingQueue


元素必须实现Comparable接口,在第一次调用take方法的时候才会被排序

public class Task implements Comparable<Task>{

    private int id ;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
} @Override
public int compareTo(Task task) {
return this.id > task.id ? 1 : (this.id < task.id ? -1 : 0);
} public String toString(){
return this.id + "," + this.name;
} } import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.PriorityBlockingQueue; public class UsePriorityBlockingQueue { public static void main(String[] args) throws Exception{ PriorityBlockingQueue<Task> q = new PriorityBlockingQueue<Task>(); Task t1 = new Task();
t1.setId(3);
t1.setName("id为3");
Task t2 = new Task();
t2.setId(4);
t2.setName("id为4");
Task t3 = new Task();
t3.setId(1);
t3.setName("id为1"); //return this.id > task.id ? 1 : 0;
q.add(t1); //
q.add(t2); //
q.add(t3); //1 // 1 3 4
System.out.println("容器:" + q);
System.out.println(q.take().getId());
System.out.println("容器:" + q);
// System.out.println(q.take().getId());
// System.out.println(q.take().getId()); }
}

六、DelayQueue 延迟队列

元素需要实现Delayed接口,DelayQueue是没有大小限制的队列。调用take方法不会立即拿到元素,得等到设定的延迟时间到了才能拿到元素。下面是网吧上网流程使用DelayQueue的例子。

 package com.bjsxt.base.coll013;

 import java.util.concurrent.DelayQueue;

 public class WangBa implements Runnable {  

     private DelayQueue<Wangmin> queue = new DelayQueue<Wangmin>();  

     public boolean yinye =true;  

     public void shangji(String name,String id,int money){
Wangmin man = new Wangmin(name, id, 1000 * money + System.currentTimeMillis());
System.out.println("网名"+man.getName()+" 身份证"+man.getId()+"交钱"+money+"块,开始上机...");
this.queue.add(man);
} public void xiaji(Wangmin man){
System.out.println("网名"+man.getName()+" 身份证"+man.getId()+"时间到下机...");
} @Override
public void run() {
while(yinye){
try {
Wangmin man = queue.take();
xiaji(man);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} public static void main(String args[]){
try{
System.out.println("网吧开始营业");
WangBa siyu = new WangBa();
Thread shangwang = new Thread(siyu);
shangwang.start(); siyu.shangji("路人甲", "123", 1);
siyu.shangji("路人乙", "234", 10);
siyu.shangji("路人丙", "345", 5);
}
catch(Exception e){
e.printStackTrace();
} }
} -------------------------------------------------------- package com.bjsxt.base.coll013; import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit; public class Wangmin implements Delayed { private String name;
//身份证
private String id;
//截止时间
private long endTime;
//定义时间工具类
private TimeUnit timeUnit = TimeUnit.SECONDS; public Wangmin(String name,String id,long endTime){
this.name=name;
this.id=id;
this.endTime = endTime;
} public String getName(){
return this.name;
} public String getId(){
return this.id;
} /**
* 用来判断是否到了截止时间
*/
@Override
public long getDelay(TimeUnit unit) {
//return unit.convert(endTime, TimeUnit.MILLISECONDS) - unit.convert(System.currentTimeMillis(), TimeUnit.MILLISECONDS);
return endTime - System.currentTimeMillis();
} /**
* 相互批较排序用
*/
@Override
public int compareTo(Delayed delayed) {
Wangmin w = (Wangmin)delayed;
return this.getDelay(this.timeUnit) - w.getDelay(this.timeUnit) > 0 ? 1:0;
} }

架构师养成记--8.Queue的更多相关文章

  1. 架构师养成记--11.Executor概述

    常用方法 Executors.newFiexdPool(int nThreads);固定线程数量的线程池: Executors.newSingleThreadExecutor();单个线程的线程池: ...

  2. 架构师养成记--35.redis集群搭建

    前记:redis哨兵经验之谈.哨兵做主从切换可能要花费一两秒,这一两秒可能会丢失很多数据.解决方法之一是在java代码中做控制,try catch 到 链接断开的异常就sleep 一两秒钟再conti ...

  3. 架构师养成记--15.Disruptor并发框架

    一.概述 disruptor对于处理并发任务很擅长,曾有人测过,一个线程里1s内可以处理六百万个订单,性能相当感人. 这个框架的结构大概是:数据生产端 --> 缓存 --> 消费端 缓存中 ...

  4. 架构师养成记--14.重入锁ReentrantLock 和 读写锁 ReentrantReadWriteLock

    ReentrantLock 有嗅探锁定和多路分支等功能,其实就是synchronized,wait,notify的升级. this锁定当前对象不方便,于是就有了用new Object()来作为锁的解决 ...

  5. 架构师养成记--12.Concurrent工具类CyclicBarrier和CountDownLatch

    java.util.concurrent.CyclicBarrier 一组线程共同等待,直到达到一个公共屏障点. 举个栗子,百米赛跑中,所有运动员都要等其他运动员都准备好后才能一起跑(假如没有发令员) ...

  6. 架构师养成记--10.master-worker模式

    master-worker模式是一种并行计算模式,分为master进程和worker进程两个部分,master是担任总管角色,worker才是执行具体任务的地方. 总体流程应该是这样的: 具体一点,代 ...

  7. 架构师养成记--9.future模式讲解

    什么是future模式呢?解释这个概念之前我们先来了解一个场景吧,财务系统的结账功能,这个功能可能是每个月用一次,在这一个月中相关的数据量已经积累得非常大,这一个功能需要调用好几个存储过程来完成.假如 ...

  8. 架构师养成记--6.单例和多线程、ThreadLocal

    一.ThreadLocal 使用wait/notify方式实现的线程安全,性能将受到很大影响.解决方案是用空间换时间,不用锁也能实现线程安全. 来看一个小例子,在线程内的set.get就是thread ...

  9. 架构师养成记--4.volatile关键字

    volatile修饰的变量可在多个线程间可见. 如下代码,在子线程运行期间主线程修改属性值并不对子线程产生影响,原因是子线程有自己独立的内存空间,其中有主内存中的变量副本. public class ...

随机推荐

  1. win10 安装visual studio 2015遇到的坑

    最近win7系统不知啥原因无法访问域中的网络文件,打算升级到win10体验一下.结果发现这一路有太多的坑.首先安装win10基本上算顺利,但是当进入系统后,菜单模式对于PC的鼠标来说,用起来感觉不顺手 ...

  2. Atitit mac os 版本 新特性 attilax大总结

    Atitit mac os 版本 新特性 attilax大总结 1. Macos概述1 2. 早期2 2.1. Macintosh OS (系统 1.0)  1984年2 2.2. Mac OS 7. ...

  3. 阶段一:AsyncTask的三个属性值和四个步骤

    “阶段一”是指我第一次系统地学习Android开发.这主要是对我的学习过程作个记录. 最近学到用AsyncTask来处理有关网络的操作.虽然代码看上去不是很复杂,但仍有很多地方有疑惑.所以研读了一下A ...

  4. 仿喜马拉雅实现ListView添加头布局和脚布局

     ListView添加头布局和脚布局 之前学习喜马拉雅的时候做的一个小Demo,贴出来,供大家学习参考: 如果我们当前的页面有多个接口.多种布局的话,我们一般的选择无非就是1.多布局:2.各种复杂滑动 ...

  5. 获取iPhone手机的UDID和设备名称.

    关于设备名称: iPhone的设备名称也可以在手机上面查看到:设置-通用-关于本机-名称(设备名称是可以自己改的) 关于UUID: 什么?用了iPhone这么久你不知道什么叫UDID! UDID 是由 ...

  6. 关于在安装MySQL时报错"本地计算机上的mysql服务启动后停止,某些服务在未由其他服务或程序使用时将自动停止"的解决方法

    首先将你下载的MySQL安装或者解压(对应安装版和解压版),下载地址http://dev.mysql.com/downloads/mysql/ 然后复制你安装目录中的my-default.ini,更改 ...

  7. Node.js 教程 02 - 经典的Hello World

    前言: Node.js的介绍.安装及配置,上一节都已经介绍过了,如果有不清楚的也可以留言或者直接问度娘. 本节: 本节主要以一个简单的例子简单体验一下Node.js,用到了两种方法.下面会介绍. 总之 ...

  8. hadoop常用的操作命令

    1.显示hdfs上test目录下的所有文件列表 hadoop fs -ls /test/ 2.查看hdfs中的文件内容 hadoop fs -cat /daas/bstl/term/rawdt/201 ...

  9. QString::​arg的用法

    1.用法示例1 String str = QString("%1 %2 %3 %4 %5 %6 %7 %8 %9 %10 %11").arg("1"," ...

  10. DOS下windows系统查看wifi密码

    DOS下windows系统查看wifi密码 首先,按win+R键,win键如下 弹出框中输入cmd 在弹出界面输入 netsh wlan show profiles 你可以看到你链接过的所有wifi名 ...