阻塞队列是一个在队列基础上又支持了两个附加操作的队列。
2个附加操作:
阻塞队列常用于生产者和消费者的场景,生产者是向队列里添加元素的线程,消费者是从队列里取元素的线程。简而言之,阻塞队列是生产者用来存放元素、消费者获取元素的容器。
在阻塞队列不可用的时候,上述2个附加操作提供了4种处理方式(以下来自JDK1.8文档):
从上表我们可以看出,当队列满时,如果我们插入元素,那么会有抛异常、返回特定值、阻塞和超时退出4种情况。相对于取元素(队列空)也有这4种情况。
JAVA 7 提供了7个阻塞队列,如下
①:ArrayBlockingQueue 数组结构组成的有界阻塞队列。
此队列按照先进先出(FIFO)的原则对元素进行排序,但是默认情况下不保证线程公平的访问队列,即如果队列满了,那么被阻塞在外面的线程对队列访问的顺序是不能保证线程公平(即先阻塞,先插入)的。
②:LinkedBlockingQueue一个由链表结构组成的有界阻塞队列
此队列按照先出先进的原则对元素进行排序
③:PriorityBlockingQueue支持优先级的无界阻塞队列
④:DelayQueue支持延时获取元素的无界阻塞队列,即可以指定多久才能从队列中获取当前元素
⑤:SynchronousQueue不存储元素的阻塞队列,每一个put必须等待一个take操作,否则不能继续添加元素。并且他支持公平访问队列。
⑥:LinkedTransferQueue由链表结构组成的无界阻塞TransferQueue队列。相对于其他阻塞队列,多了tryTransfer和transfer方法
⑦:LinkedBlockingDeque链表结构的双向阻塞队列,优势在于多线程入队时,减少一半的竞争。
通知模式实现:所谓通知模式,就是当生产者往满的队列里添加元素时会阻塞住生产者,当消费者消费了一个队列中的元素后,会通知生产者当前队列可用。例如ArrayBlockingQueue使用了Condition来实现。
最后我们写一个利用阻塞队列的实现原理来实现通知的Demo:
package Graphics;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
/**
*
* @author vayne 子线程执行3次,主线程执行5次,然后如此循环20次;
*/
public class BlockingQueueDemo
{
final static Business buse = new Business();
public static void main(String[] args)
{
new Thread(new Runnable()
{
@Override
public void run()
{
// TODO Auto-generated method stub
for (int i = 0; i < 20; i++)
{
buse.sub(i);
}
}
}).start();
for (int i = 0; i < 20; i++)
{
buse.main(i);
}
System.out.println("*************************");
}
}
// 业务逻辑类
class Business
{
ArrayBlockingQueue queue1 = new ArrayBlockingQueue<>(1);
ArrayBlockingQueue queue2 = new ArrayBlockingQueue<>(1); // 2个阻塞队列,首先向2中放入一个元素,
// 先是sub线程放的时候阻塞,然后main往1中放一个并继续执行,执行完毕取出2里面的元素让sub得以执行,
// 2再取出1中的元素让main得以执行,如此往复
{
try
{
queue2.put(1);
} catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void sub(int i)
{
try
{
queue2.put(1);
} catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
for (int j = 0; j < 3; j++)
{
System.out.println("sub sub sub" + j + ", loop" + i);
}
try
{
queue1.take();
} catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void main(int i)
{
try
{
queue1.put(1);
} catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
for (int j = 0; j < 5; j++)
{
System.out.println("main" + j + ", loop " + i);
}
try
{
queue2.take();
} catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
运行结果如下:
main0, loop 0
main1, loop 0
main2, loop 0
main3, loop 0
main4, loop 0
sub sub sub0, loop0
sub sub sub1, loop0
sub sub sub2, loop0
main0, loop 1
main1, loop 1
main2, loop 1
main3, loop 1
main4, loop 1
sub sub sub0, loop1
sub sub sub1, loop1
sub sub sub2, loop1
main0, loop 2
main1, loop 2
main2, loop 2
main3, loop 2
main4, loop 2
sub sub sub0, loop2
sub sub sub1, loop2
sub sub sub2, loop2
main0, loop 3
main1, loop 3
main2, loop 3
main3, loop 3
main4, loop 3
sub sub sub0, loop3
sub sub sub1, loop3
sub sub sub2, loop3
main0, loop 4
main1, loop 4
main2, loop 4
main3, loop 4
main4, loop 4
sub sub sub0, loop4
sub sub sub1, loop4
sub sub sub2, loop4
main0, loop 5
main1, loop 5
main2, loop 5
main3, loop 5
main4, loop 5
sub sub sub0, loop5
sub sub sub1, loop5
sub sub sub2, loop5
main0, loop 6
main1, loop 6
main2, loop 6
main3, loop 6
main4, loop 6
sub sub sub0, loop6
sub sub sub1, loop6
sub sub sub2, loop6
main0, loop 7
main1, loop 7
main2, loop 7
main3, loop 7
main4, loop 7
sub sub sub0, loop7
sub sub sub1, loop7
sub sub sub2, loop7
main0, loop 8
main1, loop 8
main2, loop 8
main3, loop 8
main4, loop 8
sub sub sub0, loop8
sub sub sub1, loop8
sub sub sub2, loop8
main0, loop 9
main1, loop 9
main2, loop 9
main3, loop 9
main4, loop 9
sub sub sub0, loop9
sub sub sub1, loop9
sub sub sub2, loop9
main0, loop 10
main1, loop 10
main2, loop 10
main3, loop 10
main4, loop 10
sub sub sub0, loop10
sub sub sub1, loop10
sub sub sub2, loop10
main0, loop 11
main1, loop 11
main2, loop 11
main3, loop 11
main4, loop 11
sub sub sub0, loop11
sub sub sub1, loop11
sub sub sub2, loop11
main0, loop 12
main1, loop 12
main2, loop 12
main3, loop 12
main4, loop 12
sub sub sub0, loop12
sub sub sub1, loop12
sub sub sub2, loop12
main0, loop 13
main1, loop 13
main2, loop 13
main3, loop 13
main4, loop 13
sub sub sub0, loop13
sub sub sub1, loop13
sub sub sub2, loop13
main0, loop 14
main1, loop 14
main2, loop 14
main3, loop 14
main4, loop 14
sub sub sub0, loop14
sub sub sub1, loop14
sub sub sub2, loop14
main0, loop 15
main1, loop 15
main2, loop 15
main3, loop 15
main4, loop 15
sub sub sub0, loop15
sub sub sub1, loop15
sub sub sub2, loop15
main0, loop 16
main1, loop 16
main2, loop 16
main3, loop 16
main4, loop 16
sub sub sub0, loop16
sub sub sub1, loop16
sub sub sub2, loop16
main0, loop 17
main1, loop 17
main2, loop 17
main3, loop 17
main4, loop 17
sub sub sub0, loop17
sub sub sub1, loop17
sub sub sub2, loop17
main0, loop 18
main1, loop 18
main2, loop 18
main3, loop 18
main4, loop 18
sub sub sub0, loop18
sub sub sub1, loop18
sub sub sub2, loop18
main0, loop 19
main1, loop 19
main2, loop 19
main3, loop 19
main4, loop 19
sub sub sub0, loop19
*************************
sub sub sub1, loop19
sub sub sub2, loop19
本文的Demo可以在我的github中找到。