Java Concurrent框架之阻塞队列(Blocking queue)

引子:
大家上过操作系统的都知道“生产者-消费者(Producer-Consumer)”模型,主要讨论的是进程(线程)间的互斥和同步问题,关键是对锁(lock)的申请、独占和释放,在这里我就不罗嗦了。原先我写的Java代码如下:

ExpandedBlockStart.gif ContractedBlock.gif public   class  Producer  extends  Thread dot.gif {
InBlock.gif  
private ProductList products = ProductList.getInstance();
InBlock.gif  
ExpandedSubBlockStart.gifContractedSubBlock.gif  
public void run()dot.gif{
InBlock.gif    
int i = 0;
InBlock.gif    
ExpandedSubBlockStart.gifContractedSubBlock.gif    
while(i <= 20)dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif      
synchronized(products)dot.gif// Get lock on product list
ExpandedSubBlockStart.gifContractedSubBlock.gif
    if(products.isFull())dot.gif{
InBlock.gif      System.out.println(
"List is full");
InBlock.gif      products.notify(); 
// Release the lock
ExpandedSubBlockStart.gifContractedSubBlock.gif
    }
 elsedot.gif{
InBlock.gif      Product product 
= new Product(i++); // Produce a product
InBlock.gif
      products.put(product);
InBlock.gif      System.out.println(
"Produced product " + product.getId());
InBlock.gif      products.notify(); 
// Release lock
ExpandedSubBlockEnd.gif
    }

ExpandedSubBlockEnd.gif      }
 // Release the lock
ExpandedSubBlockEnd.gif
    }

ExpandedSubBlockEnd.gif  }

ExpandedBlockEnd.gif}

ExpandedBlockStart.gif ContractedBlock.gif public   class  Consumer  extends  Thread dot.gif {
InBlock.gif  ProductList products 
= ProductList.getInstance();
InBlock.gif  
ExpandedSubBlockStart.gifContractedSubBlock.gif  
public void run()dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif    
while(true)dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif      
synchronized(products)dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif    
try dot.gif{
InBlock.gif      products.wait(); 
// Wait for lock
InBlock.gif
      Product product = null;
InBlock.gif      
if(!(products.isEmpty()))
InBlock.gif        product 
= products.take();
InBlock.gif      
else
InBlock.gif        System.out.println(
"List is empty");
InBlock.gif      System.out.println(
"Consumed product " + product.getId()); // Get the lock
ExpandedSubBlockStart.gifContractedSubBlock.gif
    }
 catch (InterruptedException ex) dot.gif{
InBlock.gif      ex.printStackTrace();
ExpandedSubBlockEnd.gif    }

ExpandedSubBlockEnd.gif      }
 // Release the lock
ExpandedSubBlockEnd.gif
    }

ExpandedSubBlockEnd.gif  }

ExpandedBlockEnd.gif}

None.gif

None.gif import  java.util.ArrayList;
None.gif
import  java.util.List;
None.gif
ExpandedBlockStart.gifContractedBlock.gif
public   class  ProductList  dot.gif {
InBlock.gif  
private static ProductList instance = new ProductList();
InBlock.gif  
private List<Product> products; // Adapter pattern
InBlock.gif
  public static final int SIZE = 10;
InBlock.gif  
ExpandedSubBlockStart.gifContractedSubBlock.gif  
private ProductList() dot.gif{
InBlock.gif    products 
= new ArrayList<Product>(SIZE);
ExpandedSubBlockEnd.gif  }

InBlock.gif  
ExpandedSubBlockStart.gifContractedSubBlock.gif  
public static ProductList getInstance() dot.gif// Singleton pattern
InBlock.gif
    return instance;
ExpandedSubBlockEnd.gif  }

InBlock.gif  
ExpandedSubBlockStart.gifContractedSubBlock.gif  
public boolean isFull() dot.gif{
InBlock.gif    
return products.size() == SIZE;
ExpandedSubBlockEnd.gif  }

InBlock.gif  
ExpandedSubBlockStart.gifContractedSubBlock.gif  
public void put(Product product) dot.gif{
InBlock.gif    products.add(product);
ExpandedSubBlockEnd.gif  }

InBlock.gif  
ExpandedSubBlockStart.gifContractedSubBlock.gif  
public Product take() dot.gif{
InBlock.gif    
return products.remove(0);
ExpandedSubBlockEnd.gif  }

InBlock.gif  
ExpandedSubBlockStart.gifContractedSubBlock.gif  
public boolean isEmpty() dot.gif{
InBlock.gif    
return products.isEmpty();
ExpandedSubBlockEnd.gif  }

ExpandedBlockEnd.gif}

None.gif

ExpandedBlockStart.gif ContractedBlock.gif public   class  Product  dot.gif {
InBlock.gif  
private int id;
InBlock.gif  
ExpandedSubBlockStart.gifContractedSubBlock.gif  
public Product(int id) dot.gif{
InBlock.gif    
this.id = id;
ExpandedSubBlockEnd.gif  }

InBlock.gif  
ExpandedSubBlockStart.gifContractedSubBlock.gif  
public int getId() dot.gif{
InBlock.gif    
return id;
ExpandedSubBlockEnd.gif  }

ExpandedBlockEnd.gif}

None.gif

ExpandedBlockStart.gif ContractedBlock.gif public   class  Main  dot.gif {
ExpandedSubBlockStart.gifContractedSubBlock.gif  
public static void main(String[] args)dot.gif{
InBlock.gif    Producer p 
= new Producer();
InBlock.gif    Consumer c 
= new Consumer();
InBlock.gif    
InBlock.gif    p.start();
InBlock.gif    c.start();
ExpandedSubBlockEnd.gif  }

ExpandedBlockEnd.gif}

None.gif

虽然Java对信号量及原语做了更高层次的封装(wait()、notify()、notifyAll()、synchronized{}),但看完上述代码还是觉得有点麻烦,于是JDK 5在原先collection框架的基础上增加了java.util.concurrent包,封装了许多用于线程并发操作的数据结构和操作。其中的BlockingQueue接口就是封装了一个阻塞队列的接口,具体地说就是实现了一个用于消费者(多个)和生产者(多个)交换产品的中介,生产者线程在队列满时阻塞,消费者线程在队列空时阻塞,当然在没有得到锁之前两类线程均会阻塞。详细信息可以参考Java Doc。下面用BlockingQueue实现P-C模型:

ExpandedBlockStart.gif ContractedBlock.gif class  Producer  implements  Runnable  dot.gif {
InBlock.gif   
private final BlockingQueue queue;
ExpandedSubBlockStart.gifContractedSubBlock.gif   Producer(BlockingQueue q) 
dot.gif{ queue = q; }
ExpandedSubBlockStart.gifContractedSubBlock.gif   
public void run() dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif     
try dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif       
while(truedot.gif{ queue.put(produce()); }
ExpandedSubBlockStart.gifContractedSubBlock.gif     }
 catch (InterruptedException ex) dot.gifdot.gif handle dot.gif}
ExpandedSubBlockEnd.gif   }

ExpandedSubBlockStart.gifContractedSubBlock.gif   Object produce() 
dot.gifdot.gif }
ExpandedBlockEnd.gif }

None.gif
ExpandedBlockStart.gifContractedBlock.gif 
class  Consumer  implements  Runnable  dot.gif {
InBlock.gif   
private final BlockingQueue queue;
ExpandedSubBlockStart.gifContractedSubBlock.gif   Consumer(BlockingQueue q) 
dot.gif{ queue = q; }
ExpandedSubBlockStart.gifContractedSubBlock.gif   
public void run() dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif     
try dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif       
while(truedot.gif{ consume(queue.take()); }
ExpandedSubBlockStart.gifContractedSubBlock.gif     }
 catch (InterruptedException ex) dot.gifdot.gif handle dot.gif}
ExpandedSubBlockEnd.gif   }

ExpandedSubBlockStart.gifContractedSubBlock.gif   
void consume(Object x) dot.gifdot.gif }
ExpandedBlockEnd.gif }

None.gif
ExpandedBlockStart.gifContractedBlock.gif 
class  Setup  dot.gif {
ExpandedSubBlockStart.gifContractedSubBlock.gif   
void main() dot.gif{
InBlock.gif     BlockingQueue q 
= new SomeQueueImplementation();
InBlock.gif     Producer p 
= new Producer(q);
InBlock.gif     Consumer c1 
= new Consumer(q);
InBlock.gif     Consumer c2 
= new Consumer(q);
InBlock.gif     
new Thread(p).start();
InBlock.gif     
new Thread(c1).start();
InBlock.gif     
new Thread(c2).start();
ExpandedSubBlockEnd.gif   }

ExpandedBlockEnd.gif }

None.gif

可以看出代码中没有出现wait()或notify()之类的原语操作,这些操作由concurrent框架负责封装。更全面的讨论可以参考 驯服 Tiger: 并发集合(IBM)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值