Java_阻塞队列BlockingQueue接口和实现类

(一)什么是BlockingQueue?

collection接口------>Queue接口------>BlockingQueue接口----->7个实现类

java的Queue类 java queue实现类_System

  • 当阻塞队列是时,从队列中获取元素的操作将会被阻塞
  • 当阻塞队列是时,往队列里添加元素的操作将会被阻塞

想想 蛋糕店摆出十个蛋糕 卖出了才继续做 不浪费

(二)7个实现类

collection接口------>Queue接口------>BlockingQueue接口----->7个实现类

ArrayBlockingQueue【*】:由数组结构组成的有界阻塞队列。
LinkedBlockingQueue【*】:由链表结构组成的有界(但默认大小值为Interger.MAX_VALUE)阻塞队列。
PriorityBlockingQueue:支持优先级排序的无界阻塞队列。
DelayQueue:使用优先级队列实现的延迟无界阻塞队列。
SynchronousQueue【*】:不存储元素的阻塞队列,也即单个元素的队列。就好比高定,定一个做一个
LinkedTransferQueue:由链表结构组成的无界阻塞队列。
LinkedBlockingDeque:由链表结构组成的双向阻塞队列。

(三)BlockingQueue核心方法

3.1 理论

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SvucoOT4-1572022147843)(C:\Users\LENOVO\Desktop\SGG大数据笔记\noteimgs\BlockingQueue核心方法.PNG)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8ZR0stgt-1572022147844)(C:\Users\LENOVO\Desktop\SGG大数据笔记\noteimgs\BlockingQueue核心方法2.PNG)]

3.2 代码演示

用ArrayBlockingQueue实现类举例演示
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.TimeUnit;

/**
 * collection接口------>Queue接口------>BlockingQueue接口----->7个实现类
 * ArrayBlockingQueue:由**数组结构**组成的**有界阻塞队列**。
 * LinkedBlockingQueue:由**链表结构**组成的**有界**(但默认大小值为Interger.MAX_VALUE)**阻塞队列**。
 * SynchronousQueue:**不存储元素的阻塞队列**,也即单个元素的队列。就好比高定,定一个做一个。
 *
 * BlockingQueue常用的四组方法
 *
 */

public class BlockingQueueDemo {
    public static void main(String[] args) throws InterruptedException {
//        method1();
//        method2();
//        method3();
        method4();


    }

    /**
     * method1
     * 抛出异常
     * add
     * remove
     * element
     */
    public static void method1(){
        //List list = new ArrayList();
        ArrayBlockingQueue<String> blockingQueue = new ArrayBlockingQueue<>(3);

        //add
        System.out.println(blockingQueue.add("a"));//true
        System.out.println(blockingQueue.add("b"));
        System.out.println(blockingQueue.add("c"));

//        System.out.println(blockingQueue.add("x")); //抛异常

        //element 审查有没有元素和队首
        System.out.println(blockingQueue.element()); //a

        //remove
        System.out.println(blockingQueue.remove());//a
        System.out.println(blockingQueue.remove());
        System.out.println(blockingQueue.remove());
        System.out.println(blockingQueue.remove()); //抛异常

    }

    /**
     *  method2
     * 特殊值
     * add
     * remove
     * element
     */
    public static void method2(){
        //List list = new ArrayList();
        ArrayBlockingQueue<String> blockingQueue = new ArrayBlockingQueue<>(3);

        //offer
        System.out.println(blockingQueue.offer("a"));//true
        System.out.println(blockingQueue.offer("b"));
        System.out.println(blockingQueue.offer("c"));

        System.out.println(blockingQueue.offer("x")); //false

        //offer 审查有没有元素和队首
        System.out.println(blockingQueue.peek()); //a

        //poll
        System.out.println(blockingQueue.poll()); //a
        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.poll()); //null
    }


    /**
     *  method3
     * 阻塞
     * put
     * take
     */
    public static void method3() throws InterruptedException {
        //List list = new ArrayList();
        ArrayBlockingQueue<String> blockingQueue = new ArrayBlockingQueue<>(3);

        //put
        blockingQueue.put("a");//无返回
        blockingQueue.put("b");
        blockingQueue.put("c"); //这步后就会阻塞,直到取走

//        blockingQueue.put("x"); //
        System.out.println("--------");

        //take
        blockingQueue.take();
        blockingQueue.take();
        blockingQueue.take(); //3生产 3消费 程序会正常退出
//        blockingQueue.take(); //3生产 4消费 程序会阻塞 等待生产
    }


    /**
     *  method4
     * 超时
     * offer(e,time,unit)
     * poll(time,unit)
     */
    public static void method4() throws InterruptedException {
        //List list = new ArrayList();
        ArrayBlockingQueue<String> blockingQueue = new ArrayBlockingQueue<>(3);

        //offer(e,time,unit)
        System.out.println(blockingQueue.offer("a",2L, TimeUnit.SECONDS));//true
        System.out.println(blockingQueue.offer("b",2L, TimeUnit.SECONDS));
        System.out.println(blockingQueue.offer("c",2L, TimeUnit.SECONDS));

        System.out.println(blockingQueue.offer("x",2L,TimeUnit.SECONDS)); //false

        //poll(time,unit)
        System.out.println(blockingQueue.poll(2L,TimeUnit.SECONDS)); //a
        System.out.println(blockingQueue.poll(2L,TimeUnit.SECONDS));
        System.out.println(blockingQueue.poll(2L,TimeUnit.SECONDS));
        System.out.println(blockingQueue.poll(2L,TimeUnit.SECONDS)); //null

    }

}

/*
-----method1
true
true
true
Exception in thread "main" java.lang.IllegalStateException: Queue full


-----method2
true
true
true
false
a
a
b
c
null


----method4
true
true
true
false
a
b
c
null

 */

(四)阻塞队列SynchronousQueue实现类演示

没有容量 你不消费 我不生产
每一个put操作必须要等待一个take操作,否则不能继续添加元素,反之亦然
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;

/**
 * 队列之同步SynchronousQueue队列
 */
public class SynchronousQueueDemo {
    public static void main(String[] args) {

        BlockingQueue<String> blockingQueue = new SynchronousQueue<>();

        //put
        new Thread(()->{
            try {
                System.out.println(Thread.currentThread().getName()+"\tput 1");
                blockingQueue.put("1");

                System.out.println(Thread.currentThread().getName()+"\tput 2");
                blockingQueue.put("2");

                System.out.println(Thread.currentThread().getName()+"\tput 3");
                blockingQueue.put("3");

            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"AAA").start();

        //take
        new Thread(()->{
            try {
                //暂停一会儿线程
                TimeUnit.SECONDS.sleep(5);
                System.out.println(Thread.currentThread().getName()+"\t"+blockingQueue.take());
                TimeUnit.SECONDS.sleep(5);
                System.out.println(Thread.currentThread().getName()+"\t"+blockingQueue.take());
                TimeUnit.SECONDS.sleep(5);
                System.out.println(Thread.currentThread().getName()+"\t"+blockingQueue.take());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"BBB").start();

    }

}

/*
AAA	put 1
BBB	1
AAA	put 2
BBB	2
AAA	put 3
BBB	3
 */

(五)用在哪里

5.1 生产者消费者模式

5.1.1 传统版
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 传统版的生产者消费者模式,多线程消费,生产一个消费一个
 *
 * JUC中
 * sync----lock
 * wait----await
 * notify----signal
 *
 * 多线程的判断必须要用while
 *
 */

/**
 * 资源类
 *
 * Condition它更强大的地方在于:
 * 能够更加精细的控制多线程的休眠与唤醒。
 * 对于同一个锁,我们可以创建多个Condition,
 * 在不同的情况下使用不同的Condition
 *
 */
class ShareData{
    private int number = 0;
    private Lock lock =new ReentrantLock();
    private Condition condition = lock.newCondition();

    //增加方法
    public void increment() throws Exception{
        lock.lock();   //ctrl+alt+T  try-catch快捷键
        try {
            //1、判断
            while (number != 0){
                //等待 不能生产
                condition.await();
            }
            //2、干活
            number++;
            System.out.println(Thread.currentThread().getName()+"\t"+number);

            //通知唤醒
            condition.signalAll();

        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    //减少方法
    public void decrement() throws Exception{
        lock.lock();   //ctrl+alt+T  try-catch快捷键
        try {
            //1、判断
            while (number == 0){
                //等待 不能生产
                condition.await();
            }
            //2、干活
            number--;
            System.out.println(Thread.currentThread().getName()+"\t"+number);

            //通知唤醒
            condition.signalAll();

        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

}

/**
 * 一个初始值为零的变量,两个线程交替操作,一个加一,一个减一
 * 1    线程      操作(方法)      资源类
 * 2    判断      干活      通知唤醒
 * 3    防止虚假唤醒机制
 */
public class prodConsumer_TraditionDemo {
    public static void main(String[] args) {

        ShareData shareData = new ShareData();

        for (int i=0;i<5;i++) {
            new Thread(() -> {
                try {
                    shareData.increment(); //调用增加方法
                } catch (Exception e) {
                    e.printStackTrace();
                }
            },"AA").start();
        }


        for (int i=0;i<5;i++) {
            new Thread(() -> {
                try {
                    shareData.decrement();  //调用减少方法
                } catch (Exception e) {
                    e.printStackTrace();
                }
            },"BB").start();
        }

    }
}


/*
AA	1
BB	0
AA	1
BB	0
AA	1
BB	0
AA	1
BB	0
AA	1
BB	0
 */
5.1.2 阻塞队列版
【sychronized和lock的区别】
/**
 * sychronized和lock的区别
 *
 * 1 原始构成
 * sync关键字属于JVM层面,
 *      monitorenter(底层是通过moniotr对象来完成,其实wait、notify
 *      等方法也依赖于monitor对象,只有在同步块或方法中才能调用wait/
 *      notify等方法)
 *      monitorexit
 * lcok是具体类(java.util.concurrent.locks.Lock)是api层面的锁
 *
 * 2 使用方法
 * sync不需要手动去释放锁,当sync代码执行完成后系统会自动让线程释放
 *      对锁的占用
 * ReentrantLock则需要用户手动释放锁,如果没有手动释放锁,可能会出现
 *              死锁现象。需要lock()和unlock()方法配合try/finally语句块来完成。
 *
 * 3 等待可否中断
 * sync不可中断,除非抛出异常或者正常运行完成
 * ReentrantLock 可中断,1.设置超时方法
 *                         tryLock(long timeout,TimeUnit unit)
 *                      2. lcokInterruptibly()放代码块中,调用
 *                         interrupt()方法可中断
 *
 * 4 加锁是否公平
 * sync非公平锁
 * ReentrantLock两者都可以,默认非公平锁,构造方法中可以传入boolean值,
 *              true为公平锁,false为非公平锁
 *
 * 5 锁绑定多个条件Condition
 * sync没有 要么随机唤醒一个线程,要么全部唤醒线程
 * ReentrantLock用来实现分组唤醒的线程们,可以精确唤醒
 *
 *
 * 精确唤醒的例子
 * 题目:
 *  多线程之间按顺序调用,实现A->B->C三个线程启动,要求如下
 *  AA打印3次,BB打印4次,CC打印5次
 *  紧接着
 *  AA打印3次,BB打印4次,CC打印5次
 *  ...
 *  来五轮
 *
 */

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 资源类
 * 1通知2  2通知3  3通知1
 */
class ShareResource{
    private int number = 1; //A:1 B:2 C:3
    private Lock lock = new ReentrantLock();
    private Condition c1 = lock.newCondition();
    private Condition c2 = lock.newCondition();
    private Condition c3 = lock.newCondition();

    public void print3(){
        lock.lock();
        try {
            //1 判断
            while (number !=1){
                c1.await();  //private Condition c1 = lock.newCondition();
            }
            //2 干活
            for (int i = 1; i <= 3; i++) {
                System.out.println(Thread.currentThread().getName()+"\t"+i);
            }
            //3 通知
            number = 2; //1通知2  2通知3  3通知1
            c2.signal(); //只通知2 !!!!
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
    public void print4(){
        lock.lock();
        try {
            //1 判断
            while (number !=2){
                c2.await();  //private Condition c1 = lock.newCondition();
            }
            //2 干活
            for (int i = 1; i <= 4; i++) {
                System.out.println(Thread.currentThread().getName()+"\t"+i);
            }
            //3 通知
            number = 3; //2通知3
            c3.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
    public void print5(){
        lock.lock();
        try {
            //1 判断
            while (number !=3){
                c3.await();  //private Condition c1 = lock.newCondition();
            }
            //2 干活
            for (int i = 1; i <= 5; i++) {
                System.out.println(Thread.currentThread().getName()+"\t"+i);
            }
            //3 通知
            number = 1; //3通知1
            c1.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

}

public class SyncAndReentrantLockDemo {
    public static void main(String[] args) {
        ShareResource shareResource = new ShareResource();

        new Thread(()->{
            for (int i = 0; i < 5 ; i++) {
                shareResource.print3();
            }
        },"AAA").start();
        new Thread(()->{
            for (int i = 0; i < 5 ; i++) {
                shareResource.print4();
            }
        },"BBB").start();
        new Thread(()->{
            for (int i = 0; i < 5 ; i++) {
                shareResource.print5();
            }
        },"CCC").start();
    }

}


/*
AAA	1
AAA	2
AAA	3
BBB	1
BBB	2
BBB	3
BBB	4
CCC	1
CCC	2
CCC	3
CCC	4
CCC	5
AAA	1
AAA	2
AAA	3
BBB	1
BBB	2
BBB	3
BBB	4
CCC	1
CCC	2
CCC	3
CCC	4
CCC	5
AAA	1
AAA	2
AAA	3
BBB	1
BBB	2
BBB	3
BBB	4
CCC	1
CCC	2
CCC	3
CCC	4
CCC	5
AAA	1
AAA	2
AAA	3
BBB	1
BBB	2
BBB	3
BBB	4
CCC	1
CCC	2
CCC	3
CCC	4
CCC	5
AAA	1
AAA	2
AAA	3
BBB	1
BBB	2
BBB	3
BBB	4
CCC	1
CCC	2
CCC	3
CCC	4
CCC	5


 */

5.2 线程池

后续补充

5.3 消息中间件