在多线程领域,所谓阻塞,在某些情况下会挂起线程(即阻塞),一旦满足条件,被挂起的线程又会自动被唤醒。
为什么需要BlockingQueue?
好处是我们不需要关心什么时候需要阻塞线程,什么时候需要唤醒线程,因为这一切BlockingQueue已经做好阻塞的控制。
1.队列类型
黄色标记的是重点!!!
- ArrayBlockingQueue:由数组结构组成的有界阻塞队列。
- inkedBlockingQueue:有链表结构组成的队列,默认大小=为,Integer.MAX_VALUE。
- PriorityBlockingQueue:支持优先级排序的无界对列。
- DelayQueue:使用优先级队列实现的延迟无界队列。
- SynchronousQueue:不存储元素的阻塞队列,也即单个元素的队列。
- LinkedTransferQueue:由链表结构组成的无界阻塞队列。
- LinkedBlockingDeque:由链表结构组成的双向阻塞队列。
方法类型 | 抛出异常 | 特殊值 | 阻塞 | 超时 |
---|---|---|---|---|
插入 | add(e) | offer(e) | put(e) | offer(e, time, unit) |
移除 | remove() | poll() | take() | poll(time, unit) |
检查 | element() | peek() | 不可用 | 不可用 |
抛出异常 | 当阻塞队列满时,再往队列里add插入元素就会抛 IIlegalStateException 异常 当阻塞队列空时,再往队列里remove插入元素会抛 NoSuchElementException 异常 |
特殊值 | 插入方法,成功true失败false 移除方法,成功返回出队列的元素,队里里面没有就返回null |
一直阻塞 | 当阻塞队列满时,生产者线程继续往队列里put元素,队列会一直阻塞生产者线程直到put数据or响应中断退出 当阻塞队列空时,消费者线程试图从队列里take元素,队列会一直阻塞消费者线程直到队列可用。 |
超时退出 | 当阻塞队列满时,队列会阻塞生产者线程一定时间,超时后生产者线程退出 当阻塞队列空时,队列会阻塞消费者线程一定时间,超时后消费者线程退出 |
2. SynchronousQueue
SynchronousQueue没有容量
与其他BlockingQueue不同,SynchronousQueue是一个不存储元素的BlockingQueue。
每个put操作必须等待一个take操作,否则不能继续添加元素,反正依然。
public class SynchronousQueueDemo {
public static void main(String[] args) {
BlockingQueue<Integer> blockingQueue = new SynchronousQueue<>();
new Thread(() -> {
try {
System.out.println(Thread.currentThread().getName() + "\t put1");
blockingQueue.put(1);
System.out.println(Thread.currentThread().getName() + "\t put2");
blockingQueue.put(2);
System.out.println(Thread.currentThread().getName() + "\t put3");
blockingQueue.put(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
new Thread(() -> {
try {
Integer take = blockingQueue.take();
System.out.println(Thread.currentThread().getName() + "\t" + take);
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();;
}
}
3.生产者消费者问题
/**
* 资源类
*/
class ShareData {
private int number = 0;
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
public void increment() throws Exception {
lock.lock();
try {
while (number != 0) {
condition.await();
}
number++;
System.out.println(Thread.currentThread().getName() + "\t" + number);
condition.signalAll();
} finally {
lock.unlock();
}
}
public void decrement() throws Exception {
lock.lock();
try {
while (number == 0) {
condition.await();
}
number--;
System.out.println(Thread.currentThread().getName() + "\t" + number);
condition.signalAll();
} finally {
lock.unlock();
}
}
}
public class ProducerConsumerTXDemo {
public static void main(String[] args) {
final ShareData shareData = new ShareData();
for (int i = 0; i < 5; i++) {
new Thread(new Runnable() {
@Override
public void run() {
try {
for (int k = 0; k < 3; k++) {
shareData.increment();
}
} catch (Exception e) {
}
}
}, "P" + i).start();
}
for (int i = 0; i < 3; i++) {
new Thread(new Runnable() {
@Override
public void run() {
try {
for (int k = 0; k < 5; k++) {
shareData.decrement();
}
} catch (Exception e) {
}
}
}, "C" + i).start();
}
}
}
用BlockingQueue做生产者消费者
class MyResource {
// 默认开启进行生产
private volatile boolean FLAG = true;
// 用来记录生产个数
private AtomicInteger atomicInteger = new AtomicInteger();
private BlockingQueue<String> blockingQueue;
public MyResource(BlockingQueue<String> blockingQueue) {
this.blockingQueue = blockingQueue;
System.out.println(blockingQueue.getClass().getName());
}
public void increment() throws Exception {
String data = null;
boolean resultVal = false;
while (FLAG) {
// 生产+1
data = String.valueOf(atomicInteger.incrementAndGet());
resultVal = blockingQueue.offer(data, 2L, TimeUnit.SECONDS);
if (resultVal) {
System.out.println(Thread.currentThread().getName() + "\t 插入队列成功!data:" + data);
} else {
System.out.println(Thread.currentThread().getName() + "\t 插入队列失败!data:" + data);
}
Thread.sleep(1000);
}
System.out.println("生产停止");
}
public void decrement() throws Exception {
while (FLAG) {
String data = blockingQueue.poll(2L, TimeUnit.SECONDS);
if (data != null) {
System.out.println(Thread.currentThread().getName() + "\t 消费队列成功!data:" + data);
}
}
System.out.println("消费停止");
}
public void interrupt() {
System.out.println("程序中断!!");
this.FLAG = false;
}
}
public class ProducerConsumerBlockingDemo {
public static void main(String[] args) throws Exception {
final MyResource myResource = new MyResource(new ArrayBlockingQueue<>(1));
for (int i = 0; i < 5; i++) {
new Thread(new Runnable() {
@Override
public void run() {
try {
for (int k = 0; k < 3; k++) {
myResource.increment();
}
} catch (Exception e) {
}
}
}, "P" + i).start();
}
for (int i = 0; i < 3; i++) {
new Thread(new Runnable() {
@Override
public void run() {
try {
for (int k = 0; k < 5; k++) {
myResource.decrement();
}
} catch (Exception e) {
}
}
}, "C" + i).start();
}
Thread.sleep(3 * 1000);
System.out.println("==============================");
myResource.interrupt();
}
}