架构师养成记--8.Queue
一、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的更多相关文章
- 架构师养成记--11.Executor概述
常用方法 Executors.newFiexdPool(int nThreads);固定线程数量的线程池: Executors.newSingleThreadExecutor();单个线程的线程池: ...
- 架构师养成记--35.redis集群搭建
前记:redis哨兵经验之谈.哨兵做主从切换可能要花费一两秒,这一两秒可能会丢失很多数据.解决方法之一是在java代码中做控制,try catch 到 链接断开的异常就sleep 一两秒钟再conti ...
- 架构师养成记--15.Disruptor并发框架
一.概述 disruptor对于处理并发任务很擅长,曾有人测过,一个线程里1s内可以处理六百万个订单,性能相当感人. 这个框架的结构大概是:数据生产端 --> 缓存 --> 消费端 缓存中 ...
- 架构师养成记--14.重入锁ReentrantLock 和 读写锁 ReentrantReadWriteLock
ReentrantLock 有嗅探锁定和多路分支等功能,其实就是synchronized,wait,notify的升级. this锁定当前对象不方便,于是就有了用new Object()来作为锁的解决 ...
- 架构师养成记--12.Concurrent工具类CyclicBarrier和CountDownLatch
java.util.concurrent.CyclicBarrier 一组线程共同等待,直到达到一个公共屏障点. 举个栗子,百米赛跑中,所有运动员都要等其他运动员都准备好后才能一起跑(假如没有发令员) ...
- 架构师养成记--10.master-worker模式
master-worker模式是一种并行计算模式,分为master进程和worker进程两个部分,master是担任总管角色,worker才是执行具体任务的地方. 总体流程应该是这样的: 具体一点,代 ...
- 架构师养成记--9.future模式讲解
什么是future模式呢?解释这个概念之前我们先来了解一个场景吧,财务系统的结账功能,这个功能可能是每个月用一次,在这一个月中相关的数据量已经积累得非常大,这一个功能需要调用好几个存储过程来完成.假如 ...
- 架构师养成记--6.单例和多线程、ThreadLocal
一.ThreadLocal 使用wait/notify方式实现的线程安全,性能将受到很大影响.解决方案是用空间换时间,不用锁也能实现线程安全. 来看一个小例子,在线程内的set.get就是thread ...
- 架构师养成记--4.volatile关键字
volatile修饰的变量可在多个线程间可见. 如下代码,在子线程运行期间主线程修改属性值并不对子线程产生影响,原因是子线程有自己独立的内存空间,其中有主内存中的变量副本. public class ...
随机推荐
- win10 安装visual studio 2015遇到的坑
最近win7系统不知啥原因无法访问域中的网络文件,打算升级到win10体验一下.结果发现这一路有太多的坑.首先安装win10基本上算顺利,但是当进入系统后,菜单模式对于PC的鼠标来说,用起来感觉不顺手 ...
- 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. ...
- 阶段一:AsyncTask的三个属性值和四个步骤
“阶段一”是指我第一次系统地学习Android开发.这主要是对我的学习过程作个记录. 最近学到用AsyncTask来处理有关网络的操作.虽然代码看上去不是很复杂,但仍有很多地方有疑惑.所以研读了一下A ...
- 仿喜马拉雅实现ListView添加头布局和脚布局
ListView添加头布局和脚布局 之前学习喜马拉雅的时候做的一个小Demo,贴出来,供大家学习参考: 如果我们当前的页面有多个接口.多种布局的话,我们一般的选择无非就是1.多布局:2.各种复杂滑动 ...
- 获取iPhone手机的UDID和设备名称.
关于设备名称: iPhone的设备名称也可以在手机上面查看到:设置-通用-关于本机-名称(设备名称是可以自己改的) 关于UUID: 什么?用了iPhone这么久你不知道什么叫UDID! UDID 是由 ...
- 关于在安装MySQL时报错"本地计算机上的mysql服务启动后停止,某些服务在未由其他服务或程序使用时将自动停止"的解决方法
首先将你下载的MySQL安装或者解压(对应安装版和解压版),下载地址http://dev.mysql.com/downloads/mysql/ 然后复制你安装目录中的my-default.ini,更改 ...
- Node.js 教程 02 - 经典的Hello World
前言: Node.js的介绍.安装及配置,上一节都已经介绍过了,如果有不清楚的也可以留言或者直接问度娘. 本节: 本节主要以一个简单的例子简单体验一下Node.js,用到了两种方法.下面会介绍. 总之 ...
- hadoop常用的操作命令
1.显示hdfs上test目录下的所有文件列表 hadoop fs -ls /test/ 2.查看hdfs中的文件内容 hadoop fs -cat /daas/bstl/term/rawdt/201 ...
- QString::arg的用法
1.用法示例1 String str = QString("%1 %2 %3 %4 %5 %6 %7 %8 %9 %10 %11").arg("1"," ...
- DOS下windows系统查看wifi密码
DOS下windows系统查看wifi密码 首先,按win+R键,win键如下 弹出框中输入cmd 在弹出界面输入 netsh wlan show profiles 你可以看到你链接过的所有wifi名 ...