博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
java并发编程阻塞队列
阅读量:6697 次
发布时间:2019-06-25

本文共 3830 字,大约阅读时间需要 12 分钟。

在前面我们接触的队列都是非阻塞队列,比如PriorityQueue、LinkedList(LinkedList是双向链表,它实现了Dequeue接口)。

  使用非阻塞队列的时候有一个很大问题就是:它不会对当前线程产生阻塞,那么在面对类似消费者-生产者的模型时,就必须额外地实现同步策略以及线程间唤醒策略,这个实现起来就非常麻烦。但是有了阻塞队列就不一样了,它会对当前线程产生阻塞,比如一个线程从一个空的阻塞队列中取元素,此时线程会被阻塞直到阻塞队列中有了元素。当队列中有元素后,被阻塞的线程会自动被唤醒(不需要我们编写代码去唤醒)。这样提供了极大的方便性。

使用非阻塞队列的时候有一个很大问题就是:它不会对当前线程产生阻塞,那么在面对类似消费者-生产者的模型时,就必须额外地实现同步策略以及线程间唤醒策略,这个实现起来就非常麻烦。但是有了阻塞队列就不一样了,它会对当前线程产生阻塞,比如一个线程从一个空的阻塞队列中取元素,此时线程会被阻塞直到阻塞队列中有了元素。当队列中有元素后,被阻塞的线程会自动被唤醒(不需要我们编写代码去唤醒)。这样提供了极大的方便性。

使用非阻塞队列的时候有一个很大问题就是:它不会对当前线程产生阻塞,那么在面对类似消费者-生产者的模型时,就必须额外地实现同步策略以及线程间唤醒策略,这个实现起来就非常麻烦。但是有了阻塞队列就不一样了,它会对当前线程产生阻塞,比如一个线程从一个空的阻塞队列中取元素,此时线程会被阻塞直到阻塞队列中有了元素。当队列中有元素后,被阻塞的线程会自动被唤醒(不需要我们编写代码去唤醒)。这样提供了极大的方便性。

使用非阻塞队列的时候有一个很大问题就是:它不会对当前线程产生阻塞,那么在面对类似消费者-生产者的模型时,就必须额外地实现同步策略以及线程间唤醒策略,这个实现起来就非常麻烦。但是有了阻塞队列就不一样了,它会对当前线程产生阻塞,比如一个线程从一个空的阻塞队列中取元素,此时线程会被阻塞直到阻塞队列中有了元素。当队列中有元素后,被阻塞的线程会自动被唤醒(不需要我们编写代码去唤醒)。这样提供了极大的方便性。

使用非阻塞队列的时候有一个很大问题就是:它不会对当前线程产生阻塞,那么在面对类似消费者-生产者的模型时,就必须额外地实现同步策略以及线程间唤醒策略,这个实现起来就非常麻烦。但是有了阻塞队列就不一样了,它会对当前线程产生阻塞,比如一个线程从一个空的阻塞队列中取元素,此时线程会被阻塞直到阻塞队列中有了元素。当队列中有元素后,被阻塞的线程会自动被唤醒(不需要我们编写代码去唤醒)。这样提供了极大的方便性。

 

四.示例和使用场景

  下面先使用Object.wait()和Object.notify()、非阻塞队列实现生产者-消费者模式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
public 
class 
Test {
    
private 
int 
queueSize = 
10
;
    
private 
PriorityQueue<Integer> queue = 
new 
PriorityQueue<Integer>(queueSize);
     
    
public 
static 
void 
main(String[] args)  {
        
Test test = 
new 
Test();
        
Producer producer = test.
new 
Producer();
        
Consumer consumer = test.
new 
Consumer();
         
        
producer.start();
        
consumer.start();
    
}
     
    
class 
Consumer 
extends 
Thread{
         
        
@Override
        
public 
void 
run() {
            
consume();
        
}
         
        
private 
void 
consume() {
            
while
(
true
){
                
synchronized 
(queue) {
                    
while
(queue.size() == 
0
){
                        
try 
{
                            
System.out.println(
"队列空,等待数据"
);
                            
queue.wait();
                        
catch 
(InterruptedException e) {
                            
e.printStackTrace();
                            
queue.notify();
                        
}
                    
}
                    
queue.poll();          
//每次移走队首元素
                    
queue.notify();
                    
System.out.println(
"从队列取走一个元素,队列剩余"
+queue.size()+
"个元素"
);
                
}
            
}
        
}
    
}
     
    
class 
Producer 
extends 
Thread{
         
        
@Override
        
public 
void 
run() {
            
produce();
        
}
         
        
private 
void 
produce() {
            
while
(
true
){
                
synchronized 
(queue) {
                    
while
(queue.size() == queueSize){
                        
try 
{
                            
System.out.println(
"队列满,等待有空余空间"
);
                            
queue.wait();
                        
catch 
(InterruptedException e) {
                            
e.printStackTrace();
                            
queue.notify();
                        
}
                    
}
                    
queue.offer(
1
);        
//每次插入一个元素
                    
queue.notify();
                    
System.out.println(
"向队列取中插入一个元素,队列剩余空间:"
+(queueSize-queue.size()));
                
}
            
}
        
}
    
}
}

   这个是经典的生产者-消费者模式,通过阻塞队列和Object.wait()和Object.notify()实现,wait()和notify()主要用来实现线程间通信。

  具体的线程间通信方式(wait和notify的使用)在后续问章中会讲述到。

  下面是使用阻塞队列实现的生产者-消费者模式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
public 
class 
Test {
    
private 
int 
queueSize = 
10
;
    
private 
ArrayBlockingQueue<Integer> queue = 
new 
ArrayBlockingQueue<Integer>(queueSize);
     
    
public 
static 
void 
main(String[] args)  {
        
Test test = 
new 
Test();
        
Producer producer = test.
new 
Producer();
        
Consumer consumer = test.
new 
Consumer();
         
        
producer.start();
        
consumer.start();
    
}
     
    
class 
Consumer 
extends 
Thread{
         
        
@Override
        
public 
void 
run() {
            
consume();
        
}
         
        
private 
void 
consume() {
            
while
(
true
){
                
try 
{
                    
queue.take();
                    
System.out.println(
"从队列取走一个元素,队列剩余"
+queue.size()+
"个元素"
);
                
catch 
(InterruptedException e) {
                    
e.printStackTrace();
                
}
            
}
        
}
    
}
     
    
class 
Producer 
extends 
Thread{
         
        
@Override
        
public 
void 
run() {
            
produce();
        
}
         
        
private 
void 
produce() {
            
while
(
true
){
                
try 
{
                    
queue.put(
1
);
                    
System.out.println(
"向队列取中插入一个元素,队列剩余空间:"
+(queueSize-queue.size()));
                
catch 
(InterruptedException e) {
                    
e.printStackTrace();
                
}
            
}
        
}
    
}
}

   有没有发现,使用阻塞队列代码要简单得多,不需要再单独考虑同步和线程间通信的问题。

  在并发编程中,一般推荐使用阻塞队列,这样实现可以尽量地避免程序出现意外的错误。

  阻塞队列使用最经典的场景就是socket客户端数据的读取和解析,读取数据的线程不断将数据放入队列,然后解析线程不断从队列取数据解析。还有其他类似的场景,只要符合生产者-消费者模型的都可以使用阻塞队列。

转载地址:http://yfvoo.baihongyu.com/

你可能感兴趣的文章
闰秒导致MySQL服务器的CPU sys过高
查看>>
网络抓包工具 wireshark 入门教程
查看>>
shell 编程每日100行
查看>>
Sublime Text 3新建工程
查看>>
maven GroupId 和ArtifactId的含义
查看>>
Mac下运行git报错"xcrun: error: invalid active developer path .."
查看>>
基于Dubbo框架构建分布式服务
查看>>
css sprite讲解与使用实例
查看>>
Golang 特性简介
查看>>
ubuntu安装wkhtmltopdf
查看>>
JMeter处理Cookie与Session
查看>>
qml demo分析(customgeometry-贝塞尔曲线)
查看>>
zookeeper工作原理、安装配置、工具命令简介
查看>>
@查看MySQL版本的方法
查看>>
火狐浏览器Firefox如何使用插件,火狐有哪些好用的插件
查看>>
17:文字排版
查看>>
走出半生,望你归来仍是程序员
查看>>
使用Android Studio搭建Android集成开发环境
查看>>
js生成验证码并且验证
查看>>
实现一个简单的前端水印
查看>>