优点:
1.能让多个服务器之间更充分的结合
2.能对于请求
实际开发中用到的”阻塞队列“不是一个简单的数据结构,而是一个专门的服务器程序,起个名字叫“消息队列”。kafka就是业界一个比较主流的消息队列。
基于内置的阻塞队列,实现一个简单的生产者消费者模型:
//基于标准库链表和数组实现的阻塞队列
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.LinkedBlockingDeque;
public class Demo2 {
public static void main(String[] args) throws InterruptedException {
BlockingDeque<String> queue= new LinkedBlockingDeque<>();
queue.put("hello");
String s=queue.take();
}
}
实现一个自己的阻塞队列:
1.先实现一个普通的队列(可以基于数组实现,也可以基于链表实现)
2.再加上线程安全
3.再加上阻塞
class MyBlockingQueue{
//保存数据本体
private int [] data=new int[100];
//有效元素个数
private int size=0;
//队首下标
private int head=0;
//队尾下标
private int tail=0;
//入队列
public void put(int value){
//队列满了,返回
if(size== data.length){
return ;
}
data[tail]=value;
tail++;
//tail到达末尾的情况
if(tail>= data.length){
tail=0;
}
size++;
}
//出队列
public Integer take(){
//队列为空,返回非法值
if(size==0){
return null;
}
int ret=data[head];
head++;
//head到达末尾
if(head>= data.length){
head=0;
}
size--;
return ret;
}
}
public class Demo2 {
public static void main(String[] args) throws NullPointerException{
//验证队列是否能正常工作
MyBlockingQueue queue=new MyBlockingQueue();
queue.put(1);
queue.put(2);
int ret=0;
ret=queue.take();
System.out.println(ret);
ret=queue.take();
System.out.println(ret);
}
}
给整个方法加锁:
class MyBlockingQueue{
//保存数据本体
private int [] data=new int[100];
//有效元素个数
private int size=0;
//队首下标
private int head=0;
//队尾下标
private int tail=0;
//专门的锁对象
private Object locker=new Object();
//入队列
public void put(int value){
synchronized (locker){
//队列满了,返回
if(size== data.length){
return ;
}
data[tail]=value;
tail++;
//tail到达末尾的情况
if(tail>= data.length){
tail=0;
}
size++;
}
}
//出队列
public Integer take(){
synchronized (locker){
//队列为空,返回非法值
if(size==0){
return null;
}
int ret=data[head];
head++;
//head到达末尾
if(head>= data.length){
head=0;
}
size--;
return ret;
}
}
}
实现阻塞效果:使用wait和notify
put的阻塞条件:队列满;take阻塞条件:队列空
针对哪个对象加锁,就让哪个对象wait。put中的wait要用take来唤醒
public void put(int value) throws InterruptedException {
synchronized (locker){
//队列满了,返回
if(size== data.length){
//return ;
//队列满了就加锁
(1) locker.wait();
}
data[tail]=value;
tail++;
//tail到达末尾的情况
if(tail>= data.length){
tail=0;
}
size++;
//如果入队列成功,则唤醒出队列take的等待
(2) locker.notify();
}
}
//出队列
public Integer take() throws InterruptedException {
synchronized (locker){
//队列为空,返回非法值
if(size==0){
//return null;
(2) locker.wait();
}
int ret=data[head];
head++;
//head到达末尾
if(head>= data.length){
head=0;
}
size--;
//唤醒put
(1) locker.notify();
return ret;
}
}
有人等待,notify会唤醒;如果没有人等待,notify没有任何副作用。
notify只能唤醒随机的一个等待的线程,不能做到精准,要想精准唤醒,就要使用不同的锁对象
t1.wait对应t1.notify