Java阻塞队列的实现

        优先级队列:PriorityQueue: 类似于排队的方式,以某种规则判定优先级先后调用        

        阻塞队列,是一种特殊的队列,虽然同样是先进先出,但是有特殊的功能。

1. 如果队列为空,执行出队列操作时就会阻塞,直到另一个线程往队列中添加元素为止(队列不空)

2. 如果队列为满,执行入队列操作时就会阻塞,阻塞到另一个线程从队列取走元素为止(队列不满)

阻塞队列经常用于生产者消费者模型:

        这里举一个例子,假如我们一家人三口人要吃自己包的饺子,但是只有一个擀面杖,如果三个人分别自己擀面皮然后包饺子的话,会发生擀面杖竞争,影响效率,此时一个人擀面皮另外两个人包,这时就实现了一个类似于“生产者消费者模型”,效率会提升。

        但是在程序中生产者消费者模型有一个缺陷,就是耦合很高,在A服务器需要调动B服务器时,两方都需要在各自服务器中拥有对方的调用方法,当一方挂了的时候,另外一个会跟着挂,同时如果此时想再加一个C服务器,则必须改动A中的代码,此时也有可能影响到B服务器。这时候需要我们使用阻塞队列来完成“解耦” 

解耦的具体实现:

        A服务器作为生产者,将生产出的元素全部抛给一个阻塞队列1,然后其他线程从阻塞队列上提取元素消费后抛给另一个阻塞队列2,A从阻塞队列2中提取元素,这样就完成了一次低耦合的交互。这个操作可以有效地"削峰填谷"。

下面是一个阻塞队列的代码实现:

//阻塞队列
public class ThreadDemo9 {
    public static void main(String[] args) {
        MyBlocking queue = new MyBlocking();
        //实现一个生产者消费者模式
        Thread thread = new Thread(()->{
            int num = 0 ; //计数 生产了多少
            while (true){
                System.out.println("生产了:"+num);
                try {
                    queue.put(num);
                    num++;
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });
        thread.start();
        Thread thread1 = new Thread(()->{
            int num = 0;
            while (true){
                try {
                    System.out.println("消费了:"+num);
                    num = queue.take();
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });
        thread1.start();
    }

}
class MyBlocking{
    //队列
    private  int []data = new  int[1000];
    //数组长度
    private  int size=0;
    //两个箭头一个指头一个指尾 来判断是否满/空
    private int head =0 ;

    private int tail = 0;
    private  static  Object locker = new Object();
    //入队列
    public  void  put (int value) throws InterruptedException{
        synchronized (locker){
            //开始时暂时先返回return/数组满了的时候 size = length 则需要等待notify
            if (size == data.length){
                if(size == 0){
                return;
                }
                locker.wait();
            }
            //不满时可以向里面加元素 ,并且队列往后走一格
            data[tail]= value;
            tail++;
            if(tail >= data.length){
                tail =0;
            }
            size++;
            locker.notify();

        }
    }
//出队列 此时需要包装类(size没有null 包装类有)
      public  Integer take()throws  InterruptedException{
        synchronized (locker){
            if(size ==0 ){
                //return  null;
                locker.wait();
            }
            int ret = data[head];
            head++;
            if (head>= data.length){
                head = 0;
            }
            size --;
            //take成功之后 唤醒put中的等待
            locker.notify();
            return ret;

        }
      }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java阻塞队列是一种线程安全的数据结构,它提供了同步的功能,用于在多线程环境中安全地进行数据交换和通信。其实现原理主要涉及以下几个方面。 首先,阻塞队列实现会使用锁机制确保线程安全。Java中可以使用ReentrantLock或synchronized关键字来实现锁,在对队列进行操作时会对其进行加锁,保证同一时刻只有一个线程能够访问队列。 其次,阻塞队列内部会使用条件变量或信号量来实现线程间的协调与通信。当队列为空时,消费者线程需要等待直到队列有数据可取;当队列已满时,生产者线程需要等待直到队列有空位置可放入新数据。通过条件变量或信号量的等待和唤醒机制,实现了线程间的同步和互斥。 此外,阻塞队列通常还会使用一个循环数组来存储数据。循环数组在插入和删除元素时能够高效地利用已分配的内存空间,避免了频繁的扩容和内存拷贝。同时,循环数组的读写指针可以通过取模运算得到,实现环形循环。 最后,阻塞队列还会根据不同的需求提供不同的阻塞操作。例如,用于插入元素的put()方法在队列已满时会阻塞直到有空位置可用,用于获取元素的take()方法在队列为空时会阻塞直到有数据可取。这些阻塞操作的实现依赖于同步和协调机制,保证了线程安全和数据一致性。 总之,Java阻塞队列通过使用锁、条件变量或信号量、循环数组等机制,实现了线程安全和线程间的同步与通信。它是多线程编程中常用的工具,能够有效地管理数据的生产和消费,提高多线程程序的可靠性和性能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值