9、阻塞队列

引用学习(狂神说)

什么情况下我们会使用 阻塞队列:多线程并发处理,线程池的管理!

队列的阻塞和家族介绍

队列的阻塞

队列遵循先进先出(FIFO)的原则。

这FIFO是单词的缩写,对应First Input First Ouput

家族成员

首先是要讲的阻塞队列

对应的API文档:介绍了如下的实现类

父接口Queue<E>

家族的成员

 家族的成员:树形图

 所以说:BlockingQueue 不是新的东西,只是你没有接触到,它和List、Set容器的实现类都是同级的关系。

学会使用BlockingQueue队列

实现类:ArrayBlockingQueue 非阻塞队列

需要掌握的就是:队列的添加、移除操作。

添加和移除的操作对应了4组API(4组添加和移除的操作,会产生以下的效果):

1、会抛出异常

2、不会抛出异常,但是有返回值

3、阻塞、等待

4、超时等待

方法抛出异常不抛出异常,有返回值阻塞、等待超时等待
添加 add() offer() put() offer(E e, long timeout, TimeUnit unit)
移除 remove() poll() take() poll(long timeout, TimeUnit unit)
检查队首元素 element() peek() - -

抛出异常的方法

package com.zxh.blockingQueue;

import java.util.concurrent.ArrayBlockingQueue;

public class Test {
    public static void main(String[] args) {
        test1();
    }
    /**
     * 抛出异常
     */
    public static void test1(){
        // 初始化队列的大小为3
        ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue<>(3);

        // 添加方法,添加成功返回true
        System.out.println(blockingQueue.add("a"));
        System.out.println(blockingQueue.add("b"));
        System.out.println(blockingQueue.add("c"));
        System.out.println(blockingQueue.element());    // 检查队首元素
//        java.lang.IllegalStateException: Queue full:非法状态异常:队列已满
//        System.out.println(blockingQueue.add("d"));

        System.out.println(blockingQueue.remove());
        System.out.println(blockingQueue.remove());
        System.out.println(blockingQueue.remove());
//        java.util.NoSuchElementException:没有可删除的值,抛出异常
//        System.out.println(blockingQueue.remove());

    }
}

 队列已满的情况下添加:

 没有值的情况下删除:

 

不抛出异常的方法

package com.zxh.blockingQueue;

import java.util.concurrent.ArrayBlockingQueue;

public class Test {
    public static void main(String[] args) {
        test2();
    }
    
    /**
     * 不抛出异常,有返回值
     */
    public static void test2(){
        ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue<>(3);

        // 添加方法,添加成功返回true
        System.out.println(blockingQueue.offer("a"));
        System.out.println(blockingQueue.offer("b"));
        System.out.println(blockingQueue.offer("c"));
        System.out.println(blockingQueue.peek());   // 检查队首元素
//        System.out.println(blockingQueue.offer("d"));   // false,队列已满,添加失败返回false

        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.poll());
//        System.out.println(blockingQueue.poll());   // 队列为空,删除失败返回 null

    }
}

 队列已满的情况下添加:

 没有值的情况下删除:

阻塞、等待的方法

package com.zxh.blockingQueue;

import java.util.concurrent.ArrayBlockingQueue;

public class Test {
    public static void main(String[] args) throws InterruptedException {
        test3();
    }

    /**
     * 阻塞、等待
     */
    public static void test3() throws InterruptedException {
        ArrayBlockingQueue<Object> blockingQueue = new ArrayBlockingQueue<>(3);

        // 添加方法
        blockingQueue.put("a");
        blockingQueue.put("b");
        blockingQueue.put("c");
//        blockingQueue.put("d"); //如果队列已满,再次添加会一直等待有元素移除,就会造成阻塞

        // 移除方法
        System.out.println(blockingQueue.take());
        System.out.println(blockingQueue.take());
        System.out.println(blockingQueue.take());
//        System.out.println(blockingQueue.take());   //如果队列为空,再次移除会一直等待新的元素加入,就会造成阻塞

    }

}

 队列已满的情况下添加:

 没有值的情况下删除:

 

超时等待的方法

package com.zxh.blockingQueue;

import java.util.concurrent.ArrayBlockingQueue;

public class Test {
    public static void main(String[] args) throws InterruptedException {
        test4();
    }

    /**
     * 超时等待
     */
    public static void test4() throws InterruptedException {
        ArrayBlockingQueue<Object> blockingQueue = new ArrayBlockingQueue<>(3);

        // 添加方法
        System.out.println(blockingQueue.offer("a"));
        System.out.println(blockingQueue.offer("b"));
        System.out.println(blockingQueue.offer("c"));
//        offer(E e, long timeout, TimeUnit unit):e表示要添加的值,timeout等待时间,unit延迟类型
//        如果队列已满,等待2s后,终止程序,返回false
//        System.out.println(blockingQueue.offer("d", 2, TimeUnit.SECONDS));

        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.poll());
//        poll(long timeout, TimeUnit unit):timeout等待时间, unit延迟类型
//        如果队里为空,再次删除会等待2s,终止程序,返回null
//        System.out.println(blockingQueue.poll(2, TimeUnit.SECONDS));


    }

}

 队列已满的情况下添加:等待2s终止程序,返回false

 没有值的情况下删除:会等待2s,终止程序,返回null

实现类:SynchronousQueue 同步队列

同步队列SynchronousQueue

  • 1、不存储元素

  • 2、同步操作,存储一个元素后,必须要拿出来,才能再往里面存储

  • 3、当存储一个元素后,再存储元素,就会阻塞,因为需要等待元素的取出

测试同时存储2个元素的情况

public class SynchronousQueueTest {
    public static void main(String[] args) {
        BlockingQueue<String> blockingQueue = new SynchronousQueue<>();

        try {
            blockingQueue.put("A");
            blockingQueue.put("B"); // 无法再次存储,队列会阻塞,同步队列只能存再取
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
}

就会一直等待取出

 测试多个线程存取

  • 结果:每一次存储后,都会等待取出之后,才会再次存储。
package com.zxh.blockingQueue;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;

/**
 * 同步队列SynchronousQueue
 * 1、不存储元素
 * 2、同步操作,存储一个元素后,必须要拿出来,才能再往里面存储
 * 3、当存储一个元素后,再存储元素,就会阻塞,因为需要等待元素的取出
 *
 */
public class SynchronousQueueTest {
    public static void main(String[] args) {
        BlockingQueue<String> blockingQueue = new SynchronousQueue<>();

        new Thread(()->{
            try {
                System.out.println(Thread.currentThread().getName() + "=> put 1");
                blockingQueue.put("1");
                System.out.println(Thread.currentThread().getName() + "=> put 2");
                blockingQueue.put("2");
                System.out.println(Thread.currentThread().getName() + "=> put 3");
                blockingQueue.put("3");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "T1").start();
        new Thread(()->{
            try {
                TimeUnit.SECONDS.sleep(2);
                System.out.println(Thread.currentThread().getName() + "=> get 1");
                blockingQueue.take();
                TimeUnit.SECONDS.sleep(2);
                System.out.println(Thread.currentThread().getName() + "=> get 2");
                blockingQueue.take();
                TimeUnit.SECONDS.sleep(2);
                System.out.println(Thread.currentThread().getName() + "=> get 3");
                blockingQueue.take();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "T2").start();

    }
}

先存再取,同步操作

posted @ 2020-05-25 21:30  忘忧山的兰木  阅读(248)  评论(0编辑  收藏  举报
她只是想吃这个而已啊……这一定是她非常爱吃的,我居然连如此细微的幸福也夺走了……
Hide
Switch
Save