阻塞队列

Lock实现锁的原理:

    通过Node把线程构成队列,搁置除头结点外的其他线程,当头结点释放锁时唤醒下一个节点,同时更新头结点。

 

一、Condition接口

  1、Condition接口:条件对象,阻塞和唤醒线程的作用。位于java.util.concurrent.locks包下,其中有await()、signal()、signalAll()等抽象方法,只有AQS和AQLS类中有内部类实现了Condition接口

  2、ReentrantLock接口中,有内部类Sync继承自AbstractQueuedSynchronizer抽象类,AQS中又有内部类ConditionObject实现了Condition接口。(各种使用内部类包一层,可能是出于安全的考虑.不直接用ReentrantLock继承AQS能防止AQS中的api被误用)

  3、ReentrantLock的对象可以调用newCondition()这个final方法,创建一个AQS中内部类ConditionObject的对象来实现阻塞唤醒。  在LinkedBlockingQueue、LinkedBlockingDeque、ArrayBlockingQueue等阻塞队列中,其内部实现都是通过ReentrantLock创建Condition对象来实现阻塞和唤醒的。

  4、AQS中维护的队列是当前等待资源的队列,Condition中维护的队列是等待signal的队列。

  5、await():阻塞线程。类似Object类的wait()
               1.将线程包装成Node节点,添加到Condition的队列;
               2.主动释放锁,并自循环等待锁;
               3.获取到锁,清理节点与等待队列的联系;
       signal()、signalAll():发信号,唤醒线程。类似Object中的notify()、notifyAll()
               将节点从Condition的等待队列移动到AQS阻塞队列

  6、Condition对比Object的wait等方法:
               1.Object是java底层的,Condition是语言级别的,可控性和扩展性更高;
               2.Condition支持无响应中断、支持设置超时时间;
               3.Condition支持多个等待队列(new多个Condition对象即可),Object方式只有一个。

二、阻塞队列

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.*;

public class MyBlockingQueue {

    /** 存储数据的容器、总容量、当前size */
    private List<Integer> data = new ArrayList<>();
    private volatile int capacity;
    private volatile int size;
    /** 锁和Condition */
    private Lock lock = new ReentrantLock();
    private final Condition isFull = lock.newCondition();
    private final Condition isNull = lock.newCondition();

    MyBlockingQueue(int capacity) {
        this.capacity = capacity;
    }

    /** 放数据 */
    public void put(int n) {
        try {
            lock.lock();
            try {
                while (size >= capacity) {
                    System.out.println("--------队列满了,阻塞写");
                    isFull.await(); // 阻塞写入
                }
            } catch (Exception e) {
                isFull.signal();
            }
            size++;
            data.add(n);
            isNull.signal();    // 写入成功,唤醒阻塞读
        } finally {
            lock.unlock();
        }
    }

    /** 取数据 */
    public int take() {
        try {
            lock.lock();
            try {
                while (size == 0) {
                    System.out.println("--------队列空了,阻塞读");
                    isNull.await();     // 阻塞读取
                }
            } catch (Exception e) {
                isNull.signal();
            }
            size--;
            int res = data.get(0);
            data.remove(0);
            isFull.signal();    // 读取成功,唤醒阻塞写
            return res;
        } finally {
            lock.unlock();
        }
    }


    public static void main(String[] args) {
        MyBlockingQueue queue = new MyBlockingQueue(5);
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 100; i++) {
                queue.put(i);
                System.out.println("塞入" + i);
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        Thread t2 = new Thread(() -> {
            for (; ; ) {
                System.out.println("消费"+queue.take());
                try {
                    Thread.sleep(800);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

        });
        t1.start();
        t2.start();
    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值