阻塞队列:
- 取数据,在没有数据的时候处于等待阻塞状态,有数据的时候可以从队列中取出数据。
- 存数据,队列中存放的数据已满的时候处于等待状态,有空间存数据的时候可以进行存数据。
怎样实现阻塞?
对于阻塞队列需要两个方法:取数据put()方法 和 存数据get()方法。
- 使用synchronized()+wait()+notify()来实现阻塞队列。当队列中没有数据,执行get()方法时,会调用wait()方法进行阻塞,只有当执行了put()方法存数据之后,调用notify()方法,才能唤醒get()方法继续执行取数据的操作。当队列中数据已满,执行put()方法时,会调用wait()方法进行阻塞,只有当执行了get()方法取了数据之后,调用notify()方法,才能唤醒put()方法进行执行存数据的操作。
- 使用Java5中的ReentrantLock的Condition对象来实现阻塞队列。
具体实现代码:
- synchronized()+wait()+notify()
package com.learn.BlockingQueue;
import java.util.LinkedList;
import java.util.concurrent.atomic.AtomicInteger;
/**
* wait和notify实现阻塞队列(生产者——消费者)
*/
public class WaitAndNofifyQueue {
public static void main(String[] args) throws InterruptedException {
OptQueue optQueue = new OptQueue();
TheQueue theQueue = new TheQueue(3);
//取元素
GetThread getThread1 = new GetThread(optQueue,theQueue);
getThread1.setName("我来取元素了:");
getThread1.start();
Thread.sleep(1000);
//放元素
PutThread putThread1 = new PutThread(optQueue,theQueue,"A");
putThread1.setName("我放了元素A:");
putThread1.start();
Thread.sleep(1000);
PutThread putThread2 = new PutThread(optQueue,theQueue,"B");
putThread2.setName("我放了元素B:");
putThread2.start();
Thread.sleep(1000);
PutThread putThread3 = new PutThread(optQueue,theQueue,"C");
putThread3.setName("我放了元素C:");
putThread3.start();
Thread.sleep(1000);
PutThread putThread4 = new PutThread(optQueue,theQueue,"D");
putThread4.setName("我放了元素D:");
putThread4.start();
Thread.sleep(1000);
PutThread putThread5 = new PutThread(optQueue,theQueue,"E");
putThread5.setName("我放了元素E:");
putThread5.start();
//取元素
GetThread getThread2 = new GetThread(optQueue,theQueue);
getThread2.setName("我来取元素了:");
getThread2.start();
}
}
//操作队列
class OptQueue{
private final Object lock = new Object();
private Object ret;
//取元素。当队列中没有元素,则阻塞
public void get(TheQueue theQueue){
synchronized (lock){
while(theQueue.count.get() == theQueue.minSize){
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//取排在首位的元素
ret = theQueue.list.removeFirst();
//计数器-1
theQueue.count.decrementAndGet();
//此时已经有空间存放元素,可以唤醒另一个 放元素 的线程
lock.notify();
System.out.println(Thread.currentThread().getName()+"取走了元素"+ret+"此时队列的大小为"+theQueue.list.size());
}
}
//放元素。当队列中元素满了,则阻塞
public void put(Object o,TheQueue theQueue){
synchronized (lock){
while(theQueue.count.get() == theQueue.maxSize){
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//放元素
theQueue.list.add(o);
//计数器+1
theQueue.count.incrementAndGet();
//此时已经有元素,可以唤醒另一个 取元素 的线程
lock.notify();
System.out.println(Thread.currentThread().getName()+"元素"+o+"已放入,此时队列的大小为"+theQueue.list.size());
}
}
}
class TheQueue{
//1.需要一个承装元素的队列
public LinkedList<Object> list = new LinkedList<>();
//2.计数器
public AtomicInteger count = new AtomicInteger(0);
//3.队列的上限和下限
final int maxSize;
final int minSize = 0;
//4.构造方法
public TheQueue(int size){
this.maxSize = size;
}
}
//取元素的线程
class GetThread extends Thread{
OptQueue optQueue;
TheQueue theQueue;
public GetThread(OptQueue optQueue,TheQueue theQueue) {
this.optQueue = optQueue;
this.theQueue = theQueue;
}
@Override
public void run() {
super.run();
optQueue.get(theQueue);
}
}
//放元素的线程
class PutThread extends Thread{
OptQueue optQueue;
TheQueue theQueue;
Object object;
public PutThread(OptQueue optQueue,TheQueue theQueue,Object object) {
this.optQueue = optQueue;
this.theQueue = theQueue;
this.object = object;
}
@Override
public void run() {
super.run();
optQueue.put(object,theQueue);
}
}
- Java5中的ReentrantLock的Condition对象
package com.learn.BlockingQueue;
import java.util.LinkedList;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLockQueue {
public static void main(String[] args) throws InterruptedException {
OptQueueTest optQueue = new OptQueueTest();
TheQueueTest theQueue = new TheQueueTest(3);
//取元素
GetThreadTest getThread1 = new GetThreadTest(optQueue,theQueue);
getThread1.setName("我来取元素了:");
getThread1.start();
Thread.sleep(1000);
//放元素
PutThreadTest putThread1 = new PutThreadTest(optQueue,theQueue,"A");
putThread1.setName("我放了元素AA:");
putThread1.start();
Thread.sleep(1000);
PutThreadTest putThread2 = new PutThreadTest(optQueue,theQueue,"B");
putThread2.setName("我放了元素BB:");
putThread2.start();
Thread.sleep(1000);
PutThreadTest putThread3 = new PutThreadTest(optQueue,theQueue,"C");
putThread3.setName("我放了元素CC:");
putThread3.start();
Thread.sleep(1000);
PutThreadTest putThread4 = new PutThreadTest(optQueue,theQueue,"D");
putThread4.setName("我放了元素DD:");
putThread4.start();
Thread.sleep(1000);
PutThreadTest putThread5 = new PutThreadTest(optQueue,theQueue,"E");
putThread5.setName("我放了元素EE:");
putThread5.start();
//取元素
GetThreadTest getThread2 = new GetThreadTest(optQueue,theQueue);
getThread2.setName("我来取元素了:");
getThread2.start();
}
}
//操作队列
class OptQueueTest{
//声明锁
private ReentrantLock lock = new ReentrantLock();
//队列没有满的条件
private Condition notFull = lock.newCondition();
//队列不空的条件
private Condition notEmpty = lock.newCondition();
private Object ret;
//取元素。当队列中没有元素,则阻塞
public void get(TheQueueTest theQueue){
lock.lock();
try {
while(theQueue.count.get() == theQueue.minSize){
notEmpty.await();
}
//取排在首位的元素
ret = theQueue.list.removeFirst();
//计数器-1
theQueue.count.decrementAndGet();
//此时已经有空间存放元素,可以唤醒另一个 放元素 的线程
notFull.signal();
System.out.println(Thread.currentThread().getName()+"取走了元素"+ret+"此时队列的大小为"+theQueue.list.size());
} catch (InterruptedException e) {
e.printStackTrace();
}finally{
lock.unlock();
}
}
//放元素。当队列中元素满了,则阻塞
public void put(Object o,TheQueueTest theQueue){
lock.lock();
try {
while(theQueue.count.get() == theQueue.maxSize){
notFull.await();
}
//放元素
theQueue.list.add(o);
//计数器+1
theQueue.count.incrementAndGet();
//此时已经有元素,可以唤醒另一个 取元素 的线程
notEmpty.signal();
System.out.println(Thread.currentThread().getName()+"元素"+o+"已放入,此时队列的大小为"+theQueue.list.size());
} catch (InterruptedException e) {
e.printStackTrace();
}finally{
lock.unlock();
}
}
}
class TheQueueTest{
//1.需要一个承装元素的队列
public LinkedList<Object> list = new LinkedList<>();
//2.计数器
public AtomicInteger count = new AtomicInteger(0);
//3.队列的上限和下限
final int maxSize;
final int minSize = 0;
//4.构造方法
public TheQueueTest(int size){
this.maxSize = size;
}
}
//取元素的线程
class GetThreadTest extends Thread{
OptQueueTest optQueue;
TheQueueTest theQueue;
public GetThreadTest(OptQueueTest optQueue,TheQueueTest theQueue) {
this.optQueue = optQueue;
this.theQueue = theQueue;
}
@Override
public void run() {
super.run();
optQueue.get(theQueue);
}
}
//放元素的线程
class PutThreadTest extends Thread{
OptQueueTest optQueue;
TheQueueTest theQueue;
Object object;
public PutThreadTest(OptQueueTest optQueue,TheQueueTest theQueue,Object object) {
this.optQueue = optQueue;
this.theQueue = theQueue;
this.object = object;
}
@Override
public void run() {
super.run();
optQueue.put(object,theQueue);
}
}