Java阻塞队列

参考:

http://ifeve.com/blocking-queues/

https://blog.csdn.net/bohu83/article/details/80784891

1.阻塞队列

[1].当阻塞队列是空时,从队列中获取元素的操作将会被阻塞,直到其他线程往里面插入新的元素

[2].当阻塞队列是满时,往队列里添加元素的操作将会被阻塞,直到其他线程从队列里移除一个或多个或者完全清空再继续添加

Java阻塞队列_第1张图片

2.好处

[1].在多线程领域:所谓阻塞,在某些情况下会挂起线程(即阻塞),一旦条件满足,被挂起的线程又会自动被唤醒

[2].使用BlockingQueue的好处

我们不在需要关心什么时候需要阻塞线程,什么时候需要唤醒线程,因为这一切BlockingQueue都处理好了,在concurrent包发布前,在多线程环境下,程序员需要手动控制这些细节,还有兼顾安全和效率

3.架构体系

Java阻塞队列_第2张图片

[1].ArrayBlockingQueue :一个由数组结构组成的有界阻塞队列。

[2].LinkedBlockingQueue :一个由链表结构组成的有界(但大小默认值为Integer.MAX_VALUE)阻塞队列。

[3].PriorityBlockingQueue :一个支持优先级排序的无界阻塞队列。

[4].DelayQueue:一个使用优先级队列实现的无界阻塞队列。

[5].SynchronousQueue:一个不存储元素的阻塞队列,也即单个元素的队列。

[6].LinkedTransferQueue:一个由链表结构组成的无界阻塞队列。

[7].LinkedBlockingDeque:一个由链表结构组成的双向阻塞队列

4.常用方法

方法\处理方式

抛出异常

返回特殊值

一直阻塞

超时退出

插入方法

add(e)

offer(e)

put(e)

offer(e,time,unit)

移除方法

remove()

poll()

take()

poll(time,unit)

检查方法

element()

peek()

不可用

不可用

[1].抛出异常:

①.是指当阻塞队列满时候,再往队列里插入元素,会抛出IllegalStateException(“Queue full”)异常。

②.当队列为空时,从队列里获取元素时会抛出NoSuchElementException异常 。

package com.w4xj.interview.thread;



import java.util.concurrent.ArrayBlockingQueue;

import java.util.concurrent.BlockingQueue;



/**

* @Author by w4xj

* @Classname ThrowExceptionBlockingQueueFunction

* @Description TODO

* @Date 2019/5/8 12:58

* @Created by IDEA

*/

public class ThrowExceptionBlockingQueueMethod {

    public static void main(String[] args) {

        BlockingQueue blockingQueue = new ArrayBlockingQueue<>(3);



        System.out.println(blockingQueue.add("a"));

        System.out.println(blockingQueue.add("b"));

        System.out.println(blockingQueue.add("c"));

        //Exception in thread "main" java.lang.IllegalStateException: Queue full

        //System.out.println(blockingQueue.add("z"));

        //队列头元素

        blockingQueue.element();



        System.out.println(blockingQueue.remove());

        System.out.println(blockingQueue.remove());

        System.out.println(blockingQueue.remove());

        //java.util.NoSuchElementException

        //System.out.println(blockingQueue.remove());

    }

}

[2].返回特殊值:

①.插入方法会返回是否成功,成功则返回true。

②.移除方法,则是从队列里拿出一个元素,如果没有则返回null

package com.w4xj.interview.thread;





import java.util.concurrent.ArrayBlockingQueue;

import java.util.concurrent.BlockingQueue;



/**

* @Author by w4xj

* @Classname ReturnSpecialValueBlockingQueueMethod

* @Description TODO

* @Date 2019/5/8 20:05

* @Created by IDEA

*/

public class ReturnSpecialValueBlockingQueueMethod {

    public static void main(String[] args) {

        BlockingQueue blockingQueue = new ArrayBlockingQueue(3);

        System.out.println(blockingQueue.offer("a"));

        System.out.println(blockingQueue.offer("b"));

        System.out.println(blockingQueue.offer("c"));

        System.out.println(blockingQueue.offer("z"));

        System.out.println("-----------------------------------------");

        System.out.println(blockingQueue.peek());

        System.out.println("-----------------------------------------");

        System.out.println(blockingQueue.poll());

        System.out.println(blockingQueue.poll());

        System.out.println(blockingQueue.poll());

        System.out.println(blockingQueue.poll());



        /*

        打印:

            true

            true

            true

            false

            -----------------------------------------

            a

            -----------------------------------------

            a

            b

            c

            null

         */

    }

}

[3].一直阻塞:

①.当阻塞队列满时,如果生产者线程往队列里put元素,队列会一直阻塞生产者线程,直到拿到数据,或者响应中断退出。

②.当队列空时,消费者线程试图从队列里take元素,队列也会阻塞消费者线程,直到队列可用。

[4].超时退出:

①.当阻塞队列满时,队列会阻塞生产者线程一段时间,

②.如果超过一定的时间,生产者线程就会退出。

package com.w4xj.interview.thread;



import java.util.concurrent.ArrayBlockingQueue;

import java.util.concurrent.BlockingQueue;

import java.util.concurrent.TimeUnit;



/**

* @Author by w4xj

* @Classname TimeBlockingQueue

* @Description TODO

* @Date 2019/5/8 20:19

* @Created by IDEA

*/

public class TimeBlockingQueue {

    public static void main(String[] args) throws InterruptedException {

        BlockingQueue blockingQueue = new ArrayBlockingQueue(3);

        System.out.println(blockingQueue.offer("a", 2L, TimeUnit.SECONDS));

        System.out.println(blockingQueue.offer("b", 2L, TimeUnit.SECONDS));

        System.out.println(blockingQueue.offer("c", 2L, TimeUnit.SECONDS));

        System.out.println(blockingQueue.offer("z", 2L, TimeUnit.SECONDS));

        /*

        打印:

            true

            true

            true

            false

         */

    }

}

5.SynchronousQueue

[1].SynchronousQueue没有容量,与其他BlockingQueue不同,SynchronousQueue是一个不存储元素的SynchronousQueue。没一个put操作必须要等待一个take操作,否则不能继续添加元素,反之亦然

[2].代码示例

package com.w4xj.interview.thread;



import java.util.concurrent.BlockingQueue;

import java.util.concurrent.SynchronousQueue;

import java.util.concurrent.TimeUnit;



/**

* @Author by w4xj

* @Classname SynchronousQueueTest

* @Description TODO

* @Date 2019/5/8 20:37

* @Created by IDEA

*/

public class SynchronousQueueTest {

    public static void main(String[] args) {

        BlockingQueue blockingQueue = new SynchronousQueue<>();



        new Thread(() ->{

            try {

                System.out.println(Thread.currentThread().getName() + " put a");

                blockingQueue.put("a");



                System.out.println(Thread.currentThread().getName() + " put b");

                blockingQueue.put("b");



                System.out.println(Thread.currentThread().getName() + " put c");

                blockingQueue.put("c");

            } catch (InterruptedException e) {

                e.printStackTrace();

            }

        },"ThreadA").start();



        new Thread(() ->{

            try {

                //线程睡1秒

                try { TimeUnit.SECONDS.sleep(5); } catch (InterruptedException e) { e.printStackTrace(); }

                System.out.println(Thread.currentThread().getName() + " get " + blockingQueue.take());



                //线程睡1秒

                try { TimeUnit.SECONDS.sleep(5); } catch (InterruptedException e) { e.printStackTrace(); }

                System.out.println(Thread.currentThread().getName() + " get " + blockingQueue.take());



                //线程睡1秒

                try { TimeUnit.SECONDS.sleep(5); } catch (InterruptedException e) { e.printStackTrace(); }

                System.out.println(Thread.currentThread().getName() + " get " + blockingQueue.take());

            } catch (InterruptedException e) {

                e.printStackTrace();

            }

        },"ThreadB").start();



        /*

        打印:

            ThreadA put a

            ThreadB get a

            ThreadA put b

            ThreadB get b

            ThreadA put c

            ThreadB get c

         */

    }

}

6.生产消费者

[1].使用synchronized

[2].使用Lock(Lock和synchronized的对比,见Java锁)

package com.w4xj.interview.thread;



import java.util.concurrent.locks.Condition;

import java.util.concurrent.locks.Lock;

import java.util.concurrent.locks.ReentrantLock;



/**

* @Author by w4xj

* @Classname ProducerConsumerTraditional

* @Description TODO

* @Date 2019/5/8 22:14

* @Created by IDEA

*/

public class ProducerConsumerTraditional {

    public static void main(String[] args) {

        /*

        线程操作资源类

        判断干活唤醒

        防止虚假唤醒

         */

        Resource resource = new Resource();

        new Thread(() ->{

            try {

                 for (int i = 0; i < 5; i++) {

                     resource.increment();

                 }

            } catch (InterruptedException e) {

                e.printStackTrace();

            }

        },"ThreadA").start();





        new Thread(() ->{

            try {

                 for (int i = 0; i < 5; i++) {

                     resource.decrement();

                 }

            } catch (InterruptedException e) {

                e.printStackTrace();

            }

        },"ThreadB").start();





        /*

        打印:

            ThreadA    1

            ThreadB    0

            ThreadA    1

            ThreadB    0

            ThreadA    1

            ThreadB    0

            ThreadA    1

            ThreadB    0

            ThreadA    1

            ThreadB    0

         */

    }

}





class Resource{

    private int number = 0;

    private Lock lock = new ReentrantLock();

    Condition condition = lock.newCondition();

    public void increment() throws InterruptedException {

        lock.lock();

        try {

            //while防止虚假唤醒

            while (number != 0) {

                condition.await();

            }

            number++ ;

            System.out.println(Thread.currentThread().getName() + "\t" + number);

            condition.signalAll();

        }catch (Exception e){

            e.printStackTrace();

        }finally {

            lock.unlock();

        }

    }



    public void decrement() throws InterruptedException {

        lock.lock();

        try {

            //while防止虚假唤醒

            while (number == 0) {

                condition.await();

            }

            number-- ;

            System.out.println(Thread.currentThread().getName() + "\t" + number);

            condition.signalAll();

        }catch (Exception e){

            e.printStackTrace();

        }finally {

            lock.unlock();

        }

    }

}

[3].使用阻塞队列

package com.w4xj.interview.thread;



import java.util.concurrent.ArrayBlockingQueue;

import java.util.concurrent.BlockingQueue;

import java.util.concurrent.TimeUnit;

import java.util.concurrent.atomic.AtomicInteger;



/**

* @Author by w4xj

* @Classname ProducerConsumerBlockingQueue

* @Description TODO

* @Date 2019/5/10 7:38

* @Created by IDEA

*/

public class ProducerConsumerBlockingQueue {

    public static void main(String[] args) {

        CakeResouce cakeResouce = new CakeResouce(new ArrayBlockingQueue(3));



        new Thread(() ->{

            try {

                cakeResouce.produce();

            } catch (Exception e) {

                e.printStackTrace();

            }

        },"prodcuder").start();



        new Thread(() ->{

            try {

                cakeResouce.consume();

            } catch (Exception e) {

                e.printStackTrace();

            }

        },"consumer").start();



        //线程睡1秒

        try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); }



        cakeResouce.stopProduce();

        /*

        打印:

            prodcuder  生产1成功

            consumer   消费1成功

            consumer   消费2成功

            prodcuder  生产2成功

            consumer   消费3成功

            prodcuder  生产3成功

            prodcuder  生产4成功

            consumer   消费4成功

            prodcuder  生产5成功

            consumer   消费5成功

            main    嘿,停止生产了~~

            prodcuder   停止生产

            consumer   两秒钟未能成功消费,退出

            consumer    停止消费

         */



    }

}



class CakeResouce{

    /**

     * 线程执行标志

     * true:执行

     * false:停止

     */

    private volatile boolean currentFlag = true;



    private AtomicInteger atomicInteger = new AtomicInteger();



    private BlockingQueue blockingQueue = null;





    /**

     * 构造时传入队列实例

     * @param blockingQueue

     */

    public CakeResouce(BlockingQueue blockingQueue) {

        this.blockingQueue = blockingQueue;

    }



    /**

     * 生产

     * @throws Exception

     */

    public void produce() throws Exception{

        String data ;

        while (currentFlag){

            data = String.valueOf(atomicInteger.incrementAndGet());

            boolean offer = blockingQueue.offer(data, 2L, TimeUnit.SECONDS);

            if(offer){

                System.out.println(Thread.currentThread().getName() + " \t生产" + data + "成功");

            }else {

                System.out.println(Thread.currentThread().getName() + " \t生产" + data + "失败");

            }

            //线程睡400ms

            try { TimeUnit.MILLISECONDS.sleep(400); } catch (InterruptedException e) { e.printStackTrace(); }

        }

        System.out.println(Thread.currentThread().getName() + "\t 停止生产");

    }



    /**

     * 消费

     * @throws Exception

     */

    public void consume() throws Exception{

        String data ;

        while (currentFlag){

            String poll = blockingQueue.poll(2L, TimeUnit.SECONDS);

            if(null != poll && !"".equalsIgnoreCase(poll)){

                System.out.println(Thread.currentThread().getName() + " \t消费" + poll + "成功");

            }else {

                currentFlag = false;

                System.out.println(Thread.currentThread().getName() + " \t两秒钟未能成功消费,退出");

            }

            //线程睡100毫秒,防止消费x打印在生产x之前

            try { TimeUnit.MILLISECONDS.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); }

        }



        System.out.println(Thread.currentThread().getName() + "\t 停止消费");

    }



    /**

     * 停止生产

     */

    public void stopProduce(){

        currentFlag = false;

        System.out.println(Thread.currentThread().getName() + "\t 嘿,停止生产了~~");

    }



}

 

 

 

 

 

 

 

 

你可能感兴趣的:(java基础)