Java线程和多线程(十一)——BlockingQueue
这次讨论的是Java的BlockingQueue,java.util.concurrent.BlockingQueue是一个Java的队列接口,支持一系列操作,比如,在获取和移除对象的时候如果队列为空会来等待队列变成非空的,而当队列满了的时候,插入元素会等待队列中的元素被移除,保证队列有空余的空间。
Java的BlockingQueue是不能接受null的值,如果传入null将会跑出NullPointerException的。
如果看到JDK的源码的话,其中会包含一个非空检查的方法
/**
* Throws NullPointerException if argument is null.
*
* @param v the element
*/
private static void checkNotNull(Object v) {
if (v == null)
throw new NullPointerException();
}
所以一旦传入
null,就会抛出NullPointerException
Java的BlockingQueue的实现类都是线程安全的。所有的方法都是原子性的,用得都是内部锁或者是其他的并发控制机制。
Java的BlockingQueue接口是Java集合框架的一部分,可以用来实现生产者消费者的问题。开发者不需要担心队列空间是否足够生产者或者是队列中的对象是否可以让消费者来进行操作,因为这些实现都由BlockingQuene的实现来完成的。
Java提供了几种不同的BlockingQueue的实现,比如ArrayBlockingQueue,LinkedBlockingQueue,PriorityBlockingQueue,SynchronousQueue等等。
我们将通过ArrayBlockingQueue来实现生产者消费者的问题。下面就是BlockingQueue的一些开发者需要知道的方法。
put(E e):这个方法用来元素插入到队列之中。如果队列满了,那么该操作将会阻塞,等待队列重新有空间。E take():这个方法将从一个队列中获取并从队列头部移除出去。如果队列是空的,它会等待队列中的元素重新可以获取为止。
下面我们就可以通过阻塞队列来实现生产者消费者问题。
Java阻塞队列举例——消息
一个普通的Java对象可以由生产者添加到队列中,开发者也可以称之为装在或者是队列消息。
package com.sapphire.concurrency;
public class Message {
private String msg;
public Message(String str){
this.msg=str;
}
public String getMsg() {
return msg;
}
}
Java阻塞队列举例——生产者
生产者的类将会创建消息,并且将之放到队列中,参考下面的代码:
package com.sapphire.concurrency;
import java.util.concurrent.BlockingQueue;
public class Producer implements Runnable {
private BlockingQueue<Message> queue;
public Producer(BlockingQueue<Message> q){
this.queue=q;
}
@Override
public void run() {
//produce messages
for(int i=0; i<100; i++){
Message msg = new Message(""+i);
try {
Thread.sleep(i);
queue.put(msg);
System.out.println("Produced "+msg.getMsg());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//adding exit message
Message msg = new Message("exit");
try {
queue.put(msg);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
可以看得出来,run方法会将消息插入到阻塞队列之中。
Java阻塞队列举例——消费者
消费者类将会从队列中处理消息,并且当收到exit消息的时候结束,参考如下代码:
package com.sapphire.concurrency;
import java.util.concurrent.BlockingQueue;
public class Consumer implements Runnable{
private BlockingQueue<Message> queue;
public Consumer(BlockingQueue<Message> q){
this.queue=q;
}
@Override
public void run() {
try{
Message msg;
//consuming messages until exit message is received
while((msg = queue.take()).getMsg() !="exit"){
Thread.sleep(10);
System.out.println("Consumed "+msg.getMsg());
}
}catch(InterruptedException e) {
e.printStackTrace();
}
}
}
而生产者的run方法会将阻塞队列中的元素拿出来。
Java阻塞队列举例——服务
最后,我们为生产者和消费者创建了阻塞队列服务。这个生产生消费者服务将会创建固定长度的阻塞队列,并由生产者和消费者所共用。这个服务将同时启动生产者和消费者线程,代码如下:
package com.sapphire.concurrency;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
public class ProducerConsumerService {
public static void main(String[] args) {
//Creating BlockingQueue of size 10
BlockingQueue<Message> queue = new ArrayBlockingQueue<>(10);
Producer producer = new Producer(queue);
Consumer consumer = new Consumer(queue);
//starting producer to produce messages in queue
new Thread(producer).start();
//starting consumer to consume messages from queue
new Thread(consumer).start();
System.out.println("Producer and Consumer has been started");
}
}
输出如下:
roducer and Consumer has been started
Produced 0
Produced 1
Produced 2
Produced 3
Produced 4
Consumed 0
Produced 5
Consumed 1
Produced 6
Produced 7
Consumed 2
Produced 8
...
其中的Thread.sleep方法用来让生产者和消费者能够进行延时性的生产和消费message对象。
例子中使用的方法为
put(E e)方法,其实在BlockingQueue中针对将元素加入队列的方法是有三个的
1.void put(E e):当阻塞队列是限制长度的阻塞队列时,如果队列已满,put方法是会持续等待,直到队列有空余的位置的。所以这个方法其实是一个阻塞的方法。如上面的代码,当队列的长度我们限制为10的时候,如果消费者没有及时消费掉message对象,那么生产者的线程会在执行put的时候持续阻塞掉。
2.boolean add(E e):该方法和put方法的不同之处是该方法是非阻塞的,当无法将元素插入到队列中时,会抛出IlleaglaStateException。
3.boolean offer(E e):该方法其实基本和add方法是一致的,但是当队列是满的时候,offer方法返回的是false,而add方法是抛出异常。
事实上,在ArrayBlockingQueue中add实现就是调用offer的,当offer返回false的时候直接抛出异常。
Java线程和多线程(十一)——BlockingQueue的更多相关文章
- Java线程与多线程教程
本文由 ImportNew - liken 翻译自 Journaldev. Java线程是执行某些任务的轻量级进程.Java通过Thread类提供多线程支持,应用可以创建并发执行的多个线程. 应用 ...
- Java线程和多线程(十三)——Callable,Future,FutureTask
在Java多线程之中,Callable和Future的使用时非常广泛的.在之前的文章中,我们了解了关于Java线程池基础的一些内容,知道如何提交Runnable的任务.但是,Runnable的任务是无 ...
- Java线程和多线程(十二)——线程池基础
Java 线程池管理多个工作线程,其中包含了一个队列,包含着所有等待被执行的任务.开发者可以通过使用ThreadPoolExecutor来在Java中创建线程池. 线程池是Java中多线程的一个重要概 ...
- Java线程和多线程(三)——线程安全和同步
线程安全在Java中是一个很重要的课题.Java提供的多线程环境支持使用Java线程.我们都知道多线程共享一些对象实例的话,可能会在读取和更新共享数据的事后产生数据不一致问题. 线程安全 之所以会产生 ...
- Java线程和多线程(一)——线程的基本概念
Java 线程是一个轻量级执行任务的处理单元.Java提供了Thread类来支持多线程,开发者在应用中可以创建多个线程来支持并发执行任务. 在应用中存在两种类型的线程,用户线程和守护线程.当我们启动应 ...
- Java 线程与多线程
Java是一门支持多线程的编程语言! 什么是进程? 计算机中内存.处理器.IO等资源操作都要为进程进行服务. 一个进程上可以创建多个线程,线程比进程更快的处理单元,而且所占用的资源也小,多线程的应用也 ...
- Java线程和多线程(八)——Thread Dump
Java的Thread Dump就是列出JVM中所有激活状态的线程. Java Thread Dump Java Thread Dump在分析应用性能瓶颈和死锁的时候,是非常有效的. 下面将介绍多种不 ...
- java线程跟多线程
java创建线程两种方式: 1.继承Thread创建线程 /** * Created by lsf on 16/4/18. */ class NewThread extends Thread { Ne ...
- Java 线程和多线程执行过程分析
*/ .hljs { display: block; overflow-x: auto; padding: 0.5em; color: #333; background: #f8f8f8; } .hl ...
随机推荐
- easyui学习笔记2—在行内进行表格的增删改操作
第一篇笔记中记录了如何实现表格的增删改,那个是点击之后跳出来一个对话框然后进行的,这里是在表格本身上进行的操作,也很简单,但是这里发现一个版本问题,也可以说是兼容性问题. 1.首先我们看引用的js和c ...
- Linux系统中while管道的
因为项目从AIX系统迁移到了RedHat系统,之前写过的一段Shell脚本不能成功运行,经过分析,锁定了关键代码如下: readFileContent(){ currentFile=$ fileSho ...
- js 模拟百度关键字搜索与跳转
测试效果: css样式: ul{ display:none; } html代码: <input type="text" id="text" /> & ...
- 简单说一说对JavaScript原型链的理解
每一个JavaScript对象都和另一个对象相关联,相关联的这个对象就是我们所说的“原型”.每一个对象都会从原型继承属性和方法.有一个特殊的对象没有原型,就是Object,还有一种通过Object.c ...
- 图片左右滚动控件(带倒影)——重写Gallery
转http://blog.csdn.net/ryantang03/article/details/8053643 今天在网上找了些资料,做了一个图片左右滚动的Demo,类似幻灯片播放,同时,图片带倒影 ...
- sql传统的拼接带来的危害
现在大家来学习下sql是如何注入的,传统的拼接字符串会造成 注入形式就是在变量那使用<1=1>这样查询无论怎样都是正确的 -- var sql = "select name fr ...
- POJ 1328 Radar Installation(很新颖的贪心,区间贪心)
Radar Installation Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 106491 Accepted: 2 ...
- C#串口通讯
本文提供一个用C#实现串口通讯实例,亲自编写,亲测可用! 开发环境:VS2008+.net FrameWork3.5(实际上2.0应该也可以) 第一步 创建一个WinForm窗体,拉入一些界面元素 重 ...
- Nginx负载均衡+代理+ssl+压力测试
一.Tomcat安装 1.下载jdk,Tomcat,解压到/usr/local/ 2.配置jdk环境: # vim /etc/profile export JAVA_HOME=/usr/local/j ...
- DW CS5序列号
先要改host文件,以防止其连接 Adobe 的激活验证服务器 1. 用记事本编辑“C:\Windows\System32\Drivers\etc\”目录下的 hosts 文件, 在末尾加上: 127 ...