Concurrent包
java.util.concurrent包下主要包括5个部分(《Java并发编程的艺术》这书对这5个部分都有介绍,感兴趣的朋友可以去阅读):
①Collection集合类:包括并不限于ConcurrentHashMap,BlockingQueue等等。
②lock的实现类:ReentrantLock 类,读写锁,condition等。
③util类:如CountDownLatch,信号量Semaphore,Exchanger等
④atomic类:AtomicInteger,AtomicBoolean类等
⑤线程池相关:Excutor接口,ThreadPoolExcutor接口实现类等
类图结构:
脑图地址: http://www.xmind.net/m/tJy5。
阻塞队列
就是一个队列,实行FIFO的规则,然后当队列为空时,take()出队会阻塞直到其他线程调用入队操作才能继续出队操作。当队列满了的时候,put()入队会阻塞直到其他线程调用出队操作才能继续入队操作。
简单实现阻塞队列以及put()方法和take()方法
public class BlockingQueue {
private Object[] queue;
private int head;
private int tail;
private volatile int size;
BlockingQueue(int length){
head = 0;
tail = 0;
queue = new Object[length];
size = 0;
}
public void put(Object obj) throws InterruptedException{
synchronized (this){
while(this.size == queue.length){
this.wait();
}
//因为该测试程序是生产者的效率比消费者的效率要高得多,所以一般情况都是进入上面这个wait进行等待消费者消费
//而消费者消费完后还要进行一些步骤才可以到达System.out语句,所以以防出现歧义,这里生产者线程睡眠一小段时间。
Thread.sleep(10);
queue[tail] = obj;
size++;
tail++;
if(tail == queue.length){
tail = 0;
}
this.notify();
}
}
public Object take() throws InterruptedException{
Object result;
synchronized (this){
while(this.size == 0){
this.wait();
}
result = queue[head];
head++;
size--;
if(head == queue.length){
head = 0;
}
this.notify();
}
return result;
}
}
生产者类
使用类实现Runnable方法创建线程。
public class Producer implements Runnable{
private BlockingQueue bq;
Producer(BlockingQueue blockingQueue){
this.bq = blockingQueue;
}
@Override
public void run() {
for(int i = 0 ; i < 10 ; i++){
Apple apple = new Apple(i);
try {
bq.put(apple);
System.out.println("往队列里面放入id为"+ apple.getId()+"的苹果");
//需要200毫秒生产一个苹果
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
消费者类
使用类继承Thread类的方法创建线程
public class Consumer extends Thread{
private BlockingQueue bq;
Consumer(BlockingQueue blockingQueue){
this.bq = blockingQueue;
}
public void run(){
for(int i = 0 ; i < 10 ; i++){
try {
Apple apple = (Apple) bq.take();
System.out.println("拿到了id为"+apple.getId()+"的苹果来吃");
//吃一个苹果需要1000毫秒
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
测试
public class TestBlockingQueue {
public static void main(String[] args) throws InterruptedException {
BlockingQueue blockingQueue = new BlockingQueue(3);
//实现Runnable接口的类需要先创建对象
Producer producer = new Producer(blockingQueue);
new Thread(producer).start();
Thread.sleep(10); //保证输出语句的顺序
new Consumer(blockingQueue).start();
}
}
结果
从结果可以看出:我们创建了长度为3的阻塞队列,因为我们的生产者效率是比消费者效率要高的,所以队列满了的情况时有发生。当队列满了的时候,结果呈现的是需要等待消费者线程吃掉一个苹果才能继续进行入苹果的操作。